Skip to content

Commit b38cc98

Browse files
authored
Merge pull request #751 from utopia-php/dat-851
added supportForAttributes in sql adapters
2 parents b6541a9 + 7290a34 commit b38cc98

2 files changed

Lines changed: 236 additions & 48 deletions

File tree

src/Database/Database.php

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4432,15 +4432,17 @@ public function createDocument(string $collection, Document $document): Document
44324432
}
44334433
}
44344434

4435-
$structure = new Structure(
4436-
$collection,
4437-
$this->adapter->getIdAttributeType(),
4438-
$this->adapter->getMinDateTime(),
4439-
$this->adapter->getMaxDateTime(),
4440-
$this->adapter->getSupportForAttributes()
4441-
);
4442-
if (!$structure->isValid($document)) {
4443-
throw new StructureException($structure->getDescription());
4435+
if ($this->validate) {
4436+
$structure = new Structure(
4437+
$collection,
4438+
$this->adapter->getIdAttributeType(),
4439+
$this->adapter->getMinDateTime(),
4440+
$this->adapter->getMaxDateTime(),
4441+
$this->adapter->getSupportForAttributes()
4442+
);
4443+
if (!$structure->isValid($document)) {
4444+
throw new StructureException($structure->getDescription());
4445+
}
44444446
}
44454447

44464448
$document = $this->adapter->castingBefore($collection, $document);
@@ -4534,15 +4536,17 @@ public function createDocuments(
45344536

45354537
$document = $this->encode($collection, $document);
45364538

4537-
$validator = new Structure(
4538-
$collection,
4539-
$this->adapter->getIdAttributeType(),
4540-
$this->adapter->getMinDateTime(),
4541-
$this->adapter->getMaxDateTime(),
4542-
$this->adapter->getSupportForAttributes()
4543-
);
4544-
if (!$validator->isValid($document)) {
4545-
throw new StructureException($validator->getDescription());
4539+
if ($this->validate) {
4540+
$validator = new Structure(
4541+
$collection,
4542+
$this->adapter->getIdAttributeType(),
4543+
$this->adapter->getMinDateTime(),
4544+
$this->adapter->getMaxDateTime(),
4545+
$this->adapter->getSupportForAttributes()
4546+
);
4547+
if (!$validator->isValid($document)) {
4548+
throw new StructureException($validator->getDescription());
4549+
}
45464550
}
45474551

45484552
if ($this->resolveRelationships) {
@@ -5094,16 +5098,18 @@ public function updateDocument(string $collection, string $id, Document $documen
50945098

50955099
$document = $this->encode($collection, $document);
50965100

5097-
$structureValidator = new Structure(
5098-
$collection,
5099-
$this->adapter->getIdAttributeType(),
5100-
$this->adapter->getMinDateTime(),
5101-
$this->adapter->getMaxDateTime(),
5102-
$this->adapter->getSupportForAttributes(),
5103-
$old
5104-
);
5105-
if (!$structureValidator->isValid($document)) { // Make sure updated structure still apply collection rules (if any)
5106-
throw new StructureException($structureValidator->getDescription());
5101+
if ($this->validate) {
5102+
$structureValidator = new Structure(
5103+
$collection,
5104+
$this->adapter->getIdAttributeType(),
5105+
$this->adapter->getMinDateTime(),
5106+
$this->adapter->getMaxDateTime(),
5107+
$this->adapter->getSupportForAttributes(),
5108+
$old
5109+
);
5110+
if (!$structureValidator->isValid($document)) { // Make sure updated structure still apply collection rules (if any)
5111+
throw new StructureException($structureValidator->getDescription());
5112+
}
51075113
}
51085114

51095115
if ($this->resolveRelationships) {
@@ -5250,17 +5256,19 @@ public function updateDocuments(
52505256
applyDefaults: false
52515257
);
52525258

5253-
$validator = new PartialStructure(
5254-
$collection,
5255-
$this->adapter->getIdAttributeType(),
5256-
$this->adapter->getMinDateTime(),
5257-
$this->adapter->getMaxDateTime(),
5258-
$this->adapter->getSupportForAttributes(),
5259-
null // No old document available in bulk updates
5260-
);
5259+
if ($this->validate) {
5260+
$validator = new PartialStructure(
5261+
$collection,
5262+
$this->adapter->getIdAttributeType(),
5263+
$this->adapter->getMinDateTime(),
5264+
$this->adapter->getMaxDateTime(),
5265+
$this->adapter->getSupportForAttributes(),
5266+
null // No old document available in bulk updates
5267+
);
52615268

5262-
if (!$validator->isValid($updates)) {
5263-
throw new StructureException($validator->getDescription());
5269+
if (!$validator->isValid($updates)) {
5270+
throw new StructureException($validator->getDescription());
5271+
}
52645272
}
52655273

52665274
$originalLimit = $limit;
@@ -6019,17 +6027,19 @@ public function upsertDocumentsWithIncrease(
60196027
}
60206028
}
60216029

6022-
$validator = new Structure(
6023-
$collection,
6024-
$this->adapter->getIdAttributeType(),
6025-
$this->adapter->getMinDateTime(),
6026-
$this->adapter->getMaxDateTime(),
6027-
$this->adapter->getSupportForAttributes(),
6028-
$old->isEmpty() ? null : $old
6029-
);
6030+
if ($this->validate) {
6031+
$validator = new Structure(
6032+
$collection,
6033+
$this->adapter->getIdAttributeType(),
6034+
$this->adapter->getMinDateTime(),
6035+
$this->adapter->getMaxDateTime(),
6036+
$this->adapter->getSupportForAttributes(),
6037+
$old->isEmpty() ? null : $old
6038+
);
60306039

6031-
if (!$validator->isValid($document)) {
6032-
throw new StructureException($validator->getDescription());
6040+
if (!$validator->isValid($document)) {
6041+
throw new StructureException($validator->getDescription());
6042+
}
60336043
}
60346044

60356045
$document = $this->encode($collection, $document);

tests/e2e/Adapter/Scopes/DocumentTests.php

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6185,4 +6185,182 @@ public function testCreateUpdateDocumentsMismatch(): void
61856185
$database->deleteCollection($colName);
61866186
}
61876187

6188+
public function testBypassStructureWithSupportForAttributes(): void
6189+
{
6190+
/** @var Database $database */
6191+
$database = static::getDatabase();
6192+
// for schemaless the validation will be automatically skipped
6193+
if (!$database->getAdapter()->getSupportForAttributes()) {
6194+
$this->expectNotToPerformAssertions();
6195+
return;
6196+
}
6197+
6198+
$collectionId = 'successive_update_single';
6199+
6200+
$database->createCollection($collectionId);
6201+
$database->createAttribute($collectionId, 'attrA', Database::VAR_STRING, 50, true);
6202+
$database->createAttribute($collectionId, 'attrB', Database::VAR_STRING, 50, true);
6203+
6204+
// bypass required
6205+
$database->disableValidation();
6206+
6207+
$permissions = [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any())];
6208+
$docs = $database->createDocuments($collectionId, [
6209+
new Document(['attrA' => null,'attrB' => 'B','$permissions' => $permissions])
6210+
]);
6211+
6212+
$docs = $database->find($collectionId);
6213+
foreach ($docs as $doc) {
6214+
$this->assertArrayHasKey('attrA', $doc->getAttributes());
6215+
$this->assertNull($doc->getAttribute('attrA'));
6216+
$this->assertEquals('B', $doc->getAttribute('attrB'));
6217+
}
6218+
// reset
6219+
$database->enableValidation();
6220+
6221+
try {
6222+
$database->createDocuments($collectionId, [
6223+
new Document(['attrA' => null,'attrB' => 'B','$permissions' => $permissions])
6224+
]);
6225+
$this->fail('Failed to throw exception');
6226+
} catch (Exception $e) {
6227+
$this->assertInstanceOf(StructureException::class, $e);
6228+
}
6229+
6230+
$database->deleteCollection($collectionId);
6231+
}
6232+
6233+
public function testValidationGuardsWithNullRequired(): void
6234+
{
6235+
/** @var Database $database */
6236+
$database = static::getDatabase();
6237+
6238+
if (!$database->getAdapter()->getSupportForAttributes()) {
6239+
$this->expectNotToPerformAssertions();
6240+
return;
6241+
}
6242+
6243+
// Base collection and attributes
6244+
$collection = 'validation_guard_all';
6245+
$database->createCollection($collection, permissions: [
6246+
Permission::read(Role::any()),
6247+
Permission::create(Role::any()),
6248+
Permission::update(Role::any()),
6249+
Permission::delete(Role::any()),
6250+
], documentSecurity: true);
6251+
$database->createAttribute($collection, 'name', Database::VAR_STRING, 32, true);
6252+
$database->createAttribute($collection, 'age', Database::VAR_INTEGER, 0, true);
6253+
$database->createAttribute($collection, 'value', Database::VAR_INTEGER, 0, false);
6254+
6255+
// 1) createDocument with null required should fail when validation enabled, pass when disabled
6256+
try {
6257+
$database->createDocument($collection, new Document([
6258+
'$permissions' => [Permission::read(Role::any()), Permission::create(Role::any())],
6259+
'name' => null,
6260+
'age' => null,
6261+
]));
6262+
$this->fail('Failed to throw exception');
6263+
} catch (Throwable $e) {
6264+
$this->assertInstanceOf(StructureException::class, $e);
6265+
}
6266+
6267+
$database->disableValidation();
6268+
$doc = $database->createDocument($collection, new Document([
6269+
'$id' => 'created-null',
6270+
'$permissions' => [Permission::read(Role::any()), Permission::create(Role::any()), Permission::update(Role::any())],
6271+
'name' => null,
6272+
'age' => null,
6273+
]));
6274+
$this->assertEquals('created-null', $doc->getId());
6275+
$database->enableValidation();
6276+
6277+
// Seed a valid document for updates
6278+
$valid = $database->createDocument($collection, new Document([
6279+
'$id' => 'valid',
6280+
'$permissions' => [Permission::read(Role::any()), Permission::update(Role::any())],
6281+
'name' => 'ok',
6282+
'age' => 10,
6283+
]));
6284+
$this->assertEquals('valid', $valid->getId());
6285+
6286+
// 2) updateDocument set required to null should fail when validation enabled, pass when disabled
6287+
try {
6288+
$database->updateDocument($collection, 'valid', new Document([
6289+
'age' => null,
6290+
]));
6291+
$this->fail('Failed to throw exception');
6292+
} catch (Throwable $e) {
6293+
$this->assertInstanceOf(StructureException::class, $e);
6294+
}
6295+
6296+
$database->disableValidation();
6297+
$updated = $database->updateDocument($collection, 'valid', new Document([
6298+
'age' => null,
6299+
]));
6300+
$this->assertNull($updated->getAttribute('age'));
6301+
$database->enableValidation();
6302+
6303+
// Seed a few valid docs for bulk update
6304+
for ($i = 0; $i < 2; $i++) {
6305+
$database->createDocument($collection, new Document([
6306+
'$id' => 'b' . $i,
6307+
'$permissions' => [Permission::read(Role::any()), Permission::update(Role::any())],
6308+
'name' => 'ok',
6309+
'age' => 1,
6310+
]));
6311+
}
6312+
6313+
// 3) updateDocuments setting required to null should fail when validation enabled, pass when disabled
6314+
if ($database->getAdapter()->getSupportForBatchOperations()) {
6315+
try {
6316+
$database->updateDocuments($collection, new Document([
6317+
'name' => null,
6318+
]));
6319+
$this->fail('Failed to throw exception');
6320+
} catch (Throwable $e) {
6321+
$this->assertInstanceOf(StructureException::class, $e);
6322+
}
6323+
6324+
$database->disableValidation();
6325+
$count = $database->updateDocuments($collection, new Document([
6326+
'name' => null,
6327+
]));
6328+
$this->assertGreaterThanOrEqual(3, $count); // at least the seeded docs are updated
6329+
$database->enableValidation();
6330+
}
6331+
6332+
// 4) upsertDocumentsWithIncrease with null required should fail when validation enabled, pass when disabled
6333+
if ($database->getAdapter()->getSupportForUpserts()) {
6334+
try {
6335+
$database->upsertDocumentsWithIncrease(
6336+
collection: $collection,
6337+
attribute: 'value',
6338+
documents: [new Document([
6339+
'$id' => 'u1',
6340+
'name' => null, // required null
6341+
'value' => 1,
6342+
])]
6343+
);
6344+
$this->fail('Failed to throw exception');
6345+
} catch (Throwable $e) {
6346+
$this->assertInstanceOf(StructureException::class, $e);
6347+
}
6348+
6349+
$database->disableValidation();
6350+
$ucount = $database->upsertDocumentsWithIncrease(
6351+
collection: $collection,
6352+
attribute: 'value',
6353+
documents: [new Document([
6354+
'$id' => 'u1',
6355+
'name' => null,
6356+
'value' => 1,
6357+
])]
6358+
);
6359+
$this->assertEquals(1, $ucount);
6360+
$database->enableValidation();
6361+
}
6362+
6363+
// Cleanup
6364+
$database->deleteCollection($collection);
6365+
}
61886366
}

0 commit comments

Comments
 (0)