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
14 changes: 7 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 28 additions & 8 deletions src/Database/Adapter/MariaDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,31 @@ public function createDocuments(string $collection, array $documents): array
try {
$name = $this->filter($collection);

$attributeKeys = Database::INTERNAL_ATTRIBUTE_KEYS;

$hasInternalId = null;
foreach ($documents as $document) {
$attributes = $document->getAttributes();
$attributeKeys = array_merge($attributeKeys, array_keys($attributes));

if ($hasInternalId === null) {
$hasInternalId = !empty($document->getInternalId());
} elseif ($hasInternalId == empty($document->getInternalId())) {
throw new DatabaseException('All documents must have an internalId if one is set');
}
}
$attributeKeys = array_unique($attributeKeys);

if ($this->sharedTables) {
$attributeKeys[] = '_tenant';
}

$columns = [];
foreach ($attributeKeys as $key => $attribute) {
$columns[$key] = "`{$this->filter($attribute)}`";
}
$columns = '(' . \implode(', ', $columns) . ')';

$bindIndex = 0;
$batchKeys = [];
$bindValues = [];
Expand All @@ -998,6 +1023,7 @@ public function createDocuments(string $collection, array $documents): array

if (! empty($document->getInternalId())) {
$attributes['_id'] = $document->getInternalId();
$attributeKeys[] = '_id';
} else {
$documentIds[] = $document->getId();
}
Expand All @@ -1006,16 +1032,10 @@ public function createDocuments(string $collection, array $documents): array
$attributes['_tenant'] = $this->tenant;
}

$columns = [];
foreach (\array_keys($attributes) as $key => $attribute) {
$columns[$key] = "`{$this->filter($attribute)}`";
}

$columns = '(' . \implode(', ', $columns) . ')';

$bindKeys = [];

foreach ($attributes as $value) {
foreach ($attributeKeys as $key) {
$value = $attributes[$key] ?? null;
if (\is_array($value)) {
$value = \json_encode($value);
}
Expand Down
15 changes: 15 additions & 0 deletions src/Database/Adapter/Mongo.php
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,18 @@ public function createDocuments(string $collection, array $documents): array
$name = $this->getNamespace() . '_' . $this->filter($collection);

$records = [];
$hasInternalId = null;
$documents = array_map(fn ($doc) => clone $doc, $documents);

foreach ($documents as $document) {
$internalId = $document->getInternalId();

if ($hasInternalId === null) {
$hasInternalId = !empty($internalId);
} elseif ($hasInternalId == empty($internalId)) {
throw new DatabaseException('All documents must have an internalId if one is set');
}

$document->removeAttribute('$internalId');

if ($this->sharedTables) {
Expand All @@ -767,6 +778,10 @@ public function createDocuments(string $collection, array $documents): array
$record = $this->replaceChars('$', '_', (array)$document);
$record = $this->timeToMongo($record);

if (!empty($internalId)) {
$record['_id'] = $internalId;
}

$records[] = $this->removeNullKeys($record);
}

Expand Down
36 changes: 28 additions & 8 deletions src/Database/Adapter/Postgres.php
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,31 @@ public function createDocuments(string $collection, array $documents): array

try {
$name = $this->filter($collection);
$attributeKeys = Database::INTERNAL_ATTRIBUTE_KEYS;

$hasInternalId = null;
foreach ($documents as $document) {
$attributes = $document->getAttributes();
$attributeKeys = array_merge($attributeKeys, array_keys($attributes));

if ($hasInternalId === null) {
$hasInternalId = !empty($document->getInternalId());
} elseif ($hasInternalId == empty($document->getInternalId())) {
throw new DatabaseException('All documents must have an internalId if one is set');
}
}
$attributeKeys = array_unique($attributeKeys);

if ($this->sharedTables) {
$attributeKeys[] = '_tenant';
}

$columns = [];
foreach ($attributeKeys as $key => $attribute) {
$columns[$key] = "\"{$this->filter($attribute)}\"";
}
$columns = '(' . \implode(', ', $columns) . ')';

$internalIds = [];

$bindIndex = 0;
Expand All @@ -1055,22 +1080,17 @@ public function createDocuments(string $collection, array $documents): array
if (!empty($document->getInternalId())) {
$internalIds[$document->getId()] = true;
$attributes['_id'] = $document->getInternalId();
$attributeKeys[] = '_id';
}

if ($this->sharedTables) {
$attributes['_tenant'] = $this->tenant;
}

$columns = [];
foreach (\array_keys($attributes) as $key => $attribute) {
$columns[$key] = "\"{$this->filter($attribute)}\"";
}

$columns = '(' . \implode(', ', $columns) . ')';

$bindKeys = [];

foreach ($attributes as $value) {
foreach ($attributeKeys as $key) {
$value = $attributes[$key] ?? null;
if (\is_array($value)) {
$value = \json_encode($value);
}
Expand Down
7 changes: 7 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ class Database
],
];

public const INTERNAL_ATTRIBUTE_KEYS = [
'_uid',
'_createdAt',
'_updatedAt',
'_permissions',
];

public const INTERNAL_INDEXES = [
'_id',
'_uid',
Expand Down
66 changes: 66 additions & 0 deletions tests/e2e/Adapter/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -2238,6 +2238,72 @@ public function testCreateDocuments(): array
return $documents;
}

public function testCreateDocumentsWithDifferentAttributes(): void
{
$collection = 'testDiffAttributes';

static::getDatabase()->createCollection($collection);

$this->assertEquals(true, static::getDatabase()->createAttribute($collection, 'string', Database::VAR_STRING, 128, true));
$this->assertEquals(true, static::getDatabase()->createAttribute($collection, 'integer', Database::VAR_INTEGER, 0, false));
$this->assertEquals(true, static::getDatabase()->createAttribute($collection, 'bigint', Database::VAR_INTEGER, 8, false));
$this->assertEquals(true, static::getDatabase()->createAttribute($collection, 'string_default', Database::VAR_STRING, 128, false, 'default'));

$documents = [
new Document([
'$id' => 'first',
'string' => 'text📝',
'integer' => 5,
'string_default' => 'not_default',
]),
new Document([
'$id' => 'second',
'string' => 'text📝',
]),
];

$documents = static::getDatabase()->createDocuments($collection, $documents);

$this->assertEquals(2, count($documents));

$this->assertEquals('text📝', $documents[0]->getAttribute('string'));
$this->assertEquals(5, $documents[0]->getAttribute('integer'));
$this->assertEquals('not_default', $documents[0]->getAttribute('string_default'));
$this->assertEquals('text📝', $documents[1]->getAttribute('string'));
$this->assertNull($documents[1]->getAttribute('integer'));
$this->assertEquals('default', $documents[1]->getAttribute('string_default'));

/**
* Expect fail, mix of internalId and no internalId
*/
$documents = [
new Document([
'$id' => 'third',
'$internalId' => 'third',
'string' => 'text📝',
]),
new Document([
'$id' => 'fourth',
'string' => 'text📝',
]),
];

try {
static::getDatabase()->createDocuments($collection, $documents);
$this->fail('Failed to throw exception');
} catch (DatabaseException $e) {
}

$documents = array_reverse($documents);
try {
static::getDatabase()->createDocuments($collection, $documents);
$this->fail('Failed to throw exception');
} catch (DatabaseException $e) {
}

static::getDatabase()->deleteCollection($collection);
}

public function testCreateOrUpdateDocuments(): void
{
if (!static::getDatabase()->getAdapter()->getSupportForUpserts()) {
Expand Down