Skip to content

Commit 531024c

Browse files
authored
Merge pull request #716 from utopia-php/attributes-fix-schemaless
schemaless validators , tests fix
2 parents 73d2c29 + 1ce871b commit 531024c

File tree

12 files changed

+1359
-278
lines changed

12 files changed

+1359
-278
lines changed

composer.lock

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Database/Adapter/Mongo.php

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Utopia\Database\Exception\Duplicate as DuplicateException;
1515
use Utopia\Database\Exception\Timeout as TimeoutException;
1616
use Utopia\Database\Exception\Transaction as TransactionException;
17+
use Utopia\Database\Exception\Type as TypeException;
1718
use Utopia\Database\Query;
1819
use Utopia\Database\Validator\Authorization;
1920
use Utopia\Mongo\Client;
@@ -1655,15 +1656,19 @@ public function increaseDocumentAttribute(string $collection, string $id, string
16551656
}
16561657

16571658
$options = $this->getTransactionOptions();
1658-
$this->client->update(
1659-
$this->getNamespace() . '_' . $this->filter($collection),
1660-
$filters,
1661-
[
1662-
'$inc' => [$attribute => $value],
1663-
'$set' => ['_updatedAt' => $this->toMongoDatetime($updatedAt)],
1664-
],
1665-
options: $options
1666-
);
1659+
try {
1660+
$this->client->update(
1661+
$this->getNamespace() . '_' . $this->filter($collection),
1662+
$filters,
1663+
[
1664+
'$inc' => [$attribute => $value],
1665+
'$set' => ['_updatedAt' => $this->toMongoDatetime($updatedAt)],
1666+
],
1667+
options: $options
1668+
);
1669+
} catch (MongoException $e) {
1670+
throw $this->processException($e);
1671+
}
16671672

16681673
return true;
16691674
}
@@ -2323,7 +2328,18 @@ protected function buildFilter(Query $query): array
23232328
$filter[$attribute]['$nin'] = $value;
23242329
} elseif ($operator == '$in') {
23252330
if ($query->getMethod() === Query::TYPE_CONTAINS && !$query->onArray()) {
2326-
$filter[$attribute]['$regex'] = $this->createSafeRegex($value, '.*%s.*');
2331+
// contains support array values
2332+
if (is_array($value)) {
2333+
$filter['$or'] = array_map(function ($val) use ($attribute) {
2334+
return [
2335+
$attribute => [
2336+
'$regex' => $this->createSafeRegex($val, '.*%s.*', 'i')
2337+
]
2338+
];
2339+
}, $value);
2340+
} else {
2341+
$filter[$attribute]['$regex'] = $this->createSafeRegex($value, '.*%s.*');
2342+
}
23272343
} else {
23282344
$filter[$attribute]['$in'] = $query->getValues();
23292345
}
@@ -2965,6 +2981,11 @@ protected function processException(Exception $e): \Exception
29652981
return new TransactionException('No active transaction', $e->getCode(), $e);
29662982
}
29672983

2984+
// Invalid operation(MongoDB error code 14)
2985+
if ($e->getCode() === 14) {
2986+
return new TypeException('Invalid operation', $e->getCode(), $e);
2987+
}
2988+
29682989
return $e;
29692990
}
29702991

src/Database/Database.php

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3487,7 +3487,7 @@ public function getDocument(string $collection, string $id, array $queries = [],
34873487
$this->checkQueriesType($queries);
34883488

34893489
if ($this->validate) {
3490-
$validator = new DocumentValidator($attributes);
3490+
$validator = new DocumentValidator($attributes, $this->adapter->getSupportForAttributes());
34913491
if (!$validator->isValid($queries)) {
34923492
throw new QueryException($validator->getDescription());
34933493
}
@@ -5019,6 +5019,7 @@ public function updateDocuments(
50195019
$this->maxQueryValues,
50205020
$this->adapter->getMinDateTime(),
50215021
$this->adapter->getMaxDateTime(),
5022+
$this->adapter->getSupportForAttributes()
50225023
);
50235024

50245025
if (!$validator->isValid($queries)) {
@@ -5892,24 +5893,25 @@ public function increaseDocumentAttribute(
58925893
}
58935894

58945895
$collection = $this->silent(fn () => $this->getCollection($collection));
5896+
if ($this->adapter->getSupportForAttributes()) {
5897+
$attr = \array_filter($collection->getAttribute('attributes', []), function ($a) use ($attribute) {
5898+
return $a['$id'] === $attribute;
5899+
});
58955900

5896-
$attr = \array_filter($collection->getAttribute('attributes', []), function ($a) use ($attribute) {
5897-
return $a['$id'] === $attribute;
5898-
});
5899-
5900-
if (empty($attr)) {
5901-
throw new NotFoundException('Attribute not found');
5902-
}
5901+
if (empty($attr)) {
5902+
throw new NotFoundException('Attribute not found');
5903+
}
59035904

5904-
$whiteList = [
5905-
self::VAR_INTEGER,
5906-
self::VAR_FLOAT
5907-
];
5905+
$whiteList = [
5906+
self::VAR_INTEGER,
5907+
self::VAR_FLOAT
5908+
];
59085909

5909-
/** @var Document $attr */
5910-
$attr = \end($attr);
5911-
if (!\in_array($attr->getAttribute('type'), $whiteList) || $attr->getAttribute('array')) {
5912-
throw new TypeException('Attribute must be an integer or float and can not be an array.');
5910+
/** @var Document $attr */
5911+
$attr = \end($attr);
5912+
if (!\in_array($attr->getAttribute('type'), $whiteList) || $attr->getAttribute('array')) {
5913+
throw new TypeException('Attribute must be an integer or float and can not be an array.');
5914+
}
59135915
}
59145916

59155917
$document = $this->withTransaction(function () use ($collection, $id, $attribute, $value, $max) {
@@ -5990,25 +5992,27 @@ public function decreaseDocumentAttribute(
59905992

59915993
$collection = $this->silent(fn () => $this->getCollection($collection));
59925994

5993-
$attr = \array_filter($collection->getAttribute('attributes', []), function ($a) use ($attribute) {
5994-
return $a['$id'] === $attribute;
5995-
});
5995+
if ($this->adapter->getSupportForAttributes()) {
5996+
$attr = \array_filter($collection->getAttribute('attributes', []), function ($a) use ($attribute) {
5997+
return $a['$id'] === $attribute;
5998+
});
59965999

5997-
if (empty($attr)) {
5998-
throw new NotFoundException('Attribute not found');
5999-
}
6000+
if (empty($attr)) {
6001+
throw new NotFoundException('Attribute not found');
6002+
}
60006003

6001-
$whiteList = [
6002-
self::VAR_INTEGER,
6003-
self::VAR_FLOAT
6004-
];
6004+
$whiteList = [
6005+
self::VAR_INTEGER,
6006+
self::VAR_FLOAT
6007+
];
60056008

6006-
/**
6007-
* @var Document $attr
6008-
*/
6009-
$attr = \end($attr);
6010-
if (!\in_array($attr->getAttribute('type'), $whiteList) || $attr->getAttribute('array')) {
6011-
throw new TypeException('Attribute must be an integer or float and can not be an array.');
6009+
/**
6010+
* @var Document $attr
6011+
*/
6012+
$attr = \end($attr);
6013+
if (!\in_array($attr->getAttribute('type'), $whiteList) || $attr->getAttribute('array')) {
6014+
throw new TypeException('Attribute must be an integer or float and can not be an array.');
6015+
}
60126016
}
60136017

60146018
$document = $this->withTransaction(function () use ($collection, $id, $attribute, $value, $min) {
@@ -6563,7 +6567,8 @@ public function deleteDocuments(
65636567
$this->adapter->getIdAttributeType(),
65646568
$this->maxQueryValues,
65656569
$this->adapter->getMinDateTime(),
6566-
$this->adapter->getMaxDateTime()
6570+
$this->adapter->getMaxDateTime(),
6571+
$this->adapter->getSupportForAttributes()
65676572
);
65686573

65696574
if (!$validator->isValid($queries)) {
@@ -6992,6 +6997,7 @@ public function count(string $collection, array $queries = [], ?int $max = null)
69926997
$this->maxQueryValues,
69936998
$this->adapter->getMinDateTime(),
69946999
$this->adapter->getMaxDateTime(),
7000+
$this->adapter->getSupportForAttributes()
69957001
);
69967002
if (!$validator->isValid($queries)) {
69977003
throw new QueryException($validator->getDescription());
@@ -7056,6 +7062,7 @@ public function sum(string $collection, string $attribute, array $queries = [],
70567062
$this->maxQueryValues,
70577063
$this->adapter->getMinDateTime(),
70587064
$this->adapter->getMaxDateTime(),
7065+
$this->adapter->getSupportForAttributes()
70597066
);
70607067
if (!$validator->isValid($queries)) {
70617068
throw new QueryException($validator->getDescription());
@@ -7460,10 +7467,11 @@ private function validateSelections(Document $collection, array $queries): array
74607467
$keys[] = $attribute['key'] ?? $attribute['$id'];
74617468
}
74627469
}
7463-
7464-
$invalid = \array_diff($selections, $keys);
7465-
if (!empty($invalid) && !\in_array('*', $invalid)) {
7466-
throw new QueryException('Cannot select attributes: ' . \implode(', ', $invalid));
7470+
if ($this->adapter->getSupportForAttributes()) {
7471+
$invalid = \array_diff($selections, $keys);
7472+
if (!empty($invalid) && !\in_array('*', $invalid)) {
7473+
throw new QueryException('Cannot select attributes: ' . \implode(', ', $invalid));
7474+
}
74677475
}
74687476

74697477
$selections = \array_merge($selections, $relationshipSelections);

src/Database/Validator/Index.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ public function checkIndexLength(Document $index): bool
232232
return true;
233233
}
234234

235+
if (!$this->supportForAttributes) {
236+
return true;
237+
}
238+
235239
$total = 0;
236240
$lengths = $index->getAttribute('lengths', []);
237241
$attributes = $index->getAttribute('attributes', []);

src/Database/Validator/Queries/Document.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ class Document extends Queries
1111
{
1212
/**
1313
* @param array<mixed> $attributes
14+
* @param bool $supportForAttributes
1415
* @throws Exception
1516
*/
16-
public function __construct(array $attributes)
17+
public function __construct(array $attributes, $supportForAttributes = true)
1718
{
1819
$attributes[] = new \Utopia\Database\Document([
1920
'$id' => '$id',
@@ -35,7 +36,7 @@ public function __construct(array $attributes)
3536
]);
3637

3738
$validators = [
38-
new Select($attributes),
39+
new Select($attributes, $supportForAttributes),
3940
];
4041

4142
parent::__construct($validators);

src/Database/Validator/Query/Filter.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ protected function isValidAttributeAndValues(string $attribute, array $values, s
113113
return false;
114114
}
115115

116+
if (!$this->supportForAttributes && !isset($this->schema[$attribute])) {
117+
return true;
118+
}
119+
$attributeSchema = $this->schema[$attribute];
120+
116121
$attributeType = $attributeSchema['type'];
117122

118123
// If the query method is spatial-only, the attribute must be a spatial type

tests/e2e/Adapter/Base.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Tests\E2E\Adapter\Scopes\IndexTests;
1111
use Tests\E2E\Adapter\Scopes\PermissionTests;
1212
use Tests\E2E\Adapter\Scopes\RelationshipTests;
13+
use Tests\E2E\Adapter\Scopes\SchemalessTests;
1314
use Tests\E2E\Adapter\Scopes\SpatialTests;
1415
use Utopia\Database\Database;
1516
use Utopia\Database\Validator\Authorization;
@@ -25,6 +26,7 @@ abstract class Base extends TestCase
2526
use PermissionTests;
2627
use RelationshipTests;
2728
use SpatialTests;
29+
use SchemalessTests;
2830
use GeneralTests;
2931

3032
protected static string $namespace;

tests/e2e/Adapter/Scopes/AttributeTests.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1523,7 +1523,7 @@ public function testArrayAttribute(): void
15231523
));
15241524

15251525
if ($database->getAdapter()->getSupportForIndexArray()) {
1526-
if ($database->getAdapter()->getMaxIndexLength() > 0) {
1526+
if ($database->getAdapter()->getSupportForAttributes() && $database->getAdapter()->getMaxIndexLength() > 0) {
15271527
// If getMaxIndexLength() > 0 We clear length for array attributes
15281528
$database->createIndex($collection, 'indx1', Database::INDEX_KEY, ['long_size'], [], []);
15291529
$database->deleteIndex($collection, 'indx1');

0 commit comments

Comments
 (0)