Skip to content

Commit 20ea788

Browse files
committed
fix(orm): Multiple fixes
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
1 parent 71ab884 commit 20ea788

8 files changed

Lines changed: 32 additions & 24 deletions

File tree

apps/twofactor_backupcodes/lib/Db/BackupCode.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,12 @@
1313
use OCP\AppFramework\ORM\Attribute\Entity;
1414
use OCP\AppFramework\ORM\Attribute\Id;
1515
use OCP\DB\Schema\ColumnType;
16-
use OCP\Snowflake\ISnowflakeGenerator;
1716

1817
#[Entity(name: 'twofactor_backupcodes')]
1918
final class BackupCode {
20-
#[Id(generatorClass: ISnowflakeGenerator::class)]
21-
#[Column(name: 'id', type: ColumnType::String, length: 64, nullable: false)]
22-
public ?string $id = null;
19+
#[Id]
20+
#[Column(name: 'id', type: ColumnType::Integer, nullable: false)]
21+
public ?int $id = null;
2322

2423
#[Column(name: 'user_id', type: ColumnType::String, length: 64, nullable: false)]
2524
public string $userId;

lib/private/AppFramework/ORM/EntityInfo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function __construct(
8585
}
8686

8787
if ($propertyAttributes->id instanceof Id && !$propertyAttributes->column instanceof Column) {
88-
throw new \RuntimeException($this->entityClass . ' has a Id attribute on ' . $property->getName() . ' but not the corresponding required Column attribute.');
88+
throw new \RuntimeException($this->entityClass . ' has an Id attribute on ' . $property->getName() . ' but not the corresponding required Column attribute.');
8989
}
9090

9191
if ($propertyAttributes->oneToOne instanceof OneToOne

lib/private/AppFramework/ORM/EntityManager.php

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
use OCP\DB\Schema\ITable;
2020
use OCP\IDBConnection;
2121
use OCP\Server;
22-
use OCP\Snowflake\ISnowflakeGenerator;
2322

2423
final class EntityManager {
2524
public function __construct(
@@ -79,26 +78,26 @@ public function insert(object $entity): object {
7978
if ($propertyAttributes->id !== null && $propertyAttributes->column !== null) {
8079
$generatorClass = $propertyAttributes->id->generatorClass;
8180
if ($generatorClass) {
82-
if ($generatorClass === ISnowflakeGenerator::class) {
83-
$generator = Server::get($generatorClass);
84-
$values[$propertyAttributes->column->name] = $generator->nextId();
85-
$property->setValue($entity, $insert->createNamedParameter($values[$propertyAttributes->column->name]));
86-
}
87-
81+
$generator = Server::get($generatorClass);
82+
$value = $generator->nextId();
83+
$type = $this->getParameterType($propertyAttributes->column->type, false);
84+
$values[$propertyAttributes->column->name] = $insert->createNamedParameter($value, $type);
85+
$property->setValue($entity, $value);
8886
continue;
8987
}
9088

9189
if ($isComposite) {
9290
// A composite primary key can't rely on a single autoincrement column: every
9391
// part must already be set on the entity (e.g. a foreign key id, or a value
9492
// assigned by the caller) before insert() is called.
93+
/** @psalm-suppress MixedAssignment */
9594
$value = $property->getValue($entity);
9695
if ($value === null) {
9796
throw new \LogicException($entity::class . '::' . $property->getName() . ' is part of a composite primary key and must be set before insert(); it cannot rely on DB autoincrement.');
9897
}
9998

10099
if (!is_string($value) && !is_int($value)) {
101-
throw new \LogicException($entity::class . '::' . $property->getName() . ' is part of a composite primary key and must be set to a int or string before insert();.');
100+
throw new \LogicException($entity::class . '::' . $property->getName() . ' is part of a composite primary key and must be set to an int or string before insert().');
102101
}
103102

104103
$type = $this->getParameterType($propertyAttributes->column->type, false);
@@ -222,10 +221,14 @@ public function delete(object $entity): void {
222221
foreach ($entityInfo->propertiesAttributes as $propertyAttributes) {
223222
if ($propertyAttributes->id !== null && $propertyAttributes->column !== null) {
224223
$property = $propertyAttributes->property;
225-
/** @var int|string $value */
224+
/** @var int|string|null $value */
226225
$value = $property->getValue($entity);
226+
if ($value === null) {
227+
throw new \LogicException('Trying to delete an entity with no primary key set.');
228+
}
227229

228-
$delete->andWhere($delete->expr()->eq($propertyAttributes->column->name, $delete->createNamedParameter($value)));
230+
$type = $this->getParameterType($propertyAttributes->column->type, false);
231+
$delete->andWhere($delete->expr()->eq($propertyAttributes->column->name, $delete->createNamedParameter($value, $type)));
229232
$foundId = true;
230233
};
231234
}

lib/private/AppFramework/ORM/PropertyAttributes.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function getOwningRelationTarget(): ?string {
4141
return $this->manyToOne->targetEntity;
4242
}
4343

44-
if ($this->oneToOne instanceof OneToOne && $this->oneToOne->invertedBy !== null) {
44+
if ($this->oneToOne instanceof OneToOne && $this->oneToOne->mappedBy === null) {
4545
return $this->oneToOne->targetEntity;
4646
}
4747

lib/private/Tags.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ public function add(string $name): false|int {
242242
]);
243243
return false;
244244
}
245-
$this->logger->debug(__METHOD__ . ' Added an tag with ' . $tag->id, ['app' => 'core']);
245+
$this->logger->debug(__METHOD__ . ' Added a tag with ' . $tag->id, ['app' => 'core']);
246246
return $tag->id ?? false;
247247
}
248248

lib/public/AppFramework/ORM/Repository.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ private function hydrateRow(string $entityClass, mixed $row): object {
8888
continue;
8989
}
9090

91+
if ($value === null) {
92+
$entity->$property = null;
93+
continue;
94+
}
95+
9196
/** @psalm-suppress MixedAssignment $value is a raw DB driver value; each branch below settype()s or reconstructs it. */
9297
$value = match ($type) {
9398
ColumnType::Bigint, ColumnType::Smallint, ColumnType::Integer => (int)$value,
@@ -472,7 +477,8 @@ private function getJoinedSelectQueryBuilder(array $criteria, array $orderBy = [
472477
}
473478

474479
foreach ($orderBy as $field => $direction) {
475-
$qb->addOrderBy($qb->createNamedParameter($field), $direction === \SortDirection::Ascending ? 'ASC' : 'DESC');
480+
$column = $entityInfo->mappingPropertyToColumn[$field];
481+
$qb->addOrderBy('e.' . $column, $direction === \SortDirection::Ascending ? 'ASC' : 'DESC');
476482
}
477483

478484
return [$qb, $relations];

lib/public/ITags.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ public function getTag(string $id);
5353
*
5454
* ```php
5555
* [
56-
* ['id' => 0, 'name' = 'First tag', 'owner' = 'User A', 'type' => 'tagtype'],
57-
* ['id' => 1, 'name' = 'Second tag', 'owner' = 'User B', 'type' => 'tagtype'],
56+
* ['id' => 0, 'name' = 'First tag', 'owner' => 'User A', 'type' => 'tagtype'],
57+
* ['id' => 1, 'name' = 'Second tag', 'owner' => 'User B', 'type' => 'tagtype'],
5858
* ]
5959
* ```
6060
*
@@ -136,7 +136,7 @@ public function rename(string|int $from, string $to): bool;
136136
* Add a list of new tags.
137137
*
138138
* @param string|list<string> $names A string with a name or an array of strings containing
139-
* the name(s) of the to add.
139+
* the name(s) of the tags to add.
140140
* @param bool $sync When true, save the tags
141141
* @param int|null $id int Optional object id to add to this|these tag(s)
142142
* @return bool Returns false on error.

tests/lib/AppFramework/ORM/RepositoryTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ final class TypoTarget {
137137
public ?TypoOwning $owner = null;
138138
}
139139

140-
#[Entity(name: 'repository_cascade_parent')]
140+
#[Entity(name: 'repository_casc_parent')]
141141
final class CascadeParent {
142142
#[Id]
143143
#[Column(name: 'id', type: ColumnType::Bigint)]
@@ -151,7 +151,7 @@ final class CascadeParent {
151151
public ?CascadeChild $child = null;
152152
}
153153

154-
#[Entity(name: 'repository_cascade_child')]
154+
#[Entity(name: 'repository_casc_child')]
155155
final class CascadeChild {
156156
#[Id]
157157
#[Column(name: 'id', type: ColumnType::Bigint)]
@@ -214,7 +214,7 @@ public static function setUpBeforeClass(): void {
214214
public static function tearDownAfterClass(): void {
215215
$entityManager = Server::get(EntityManager::class);
216216
$prefix = Server::get(IConfig::class)->getSystemValueString('dbtableprefix', 'oc_');
217-
foreach (static::$entitiesClasses as $entityClass) {
217+
foreach (array_reverse(static::$entitiesClasses) as $entityClass) {
218218
try {
219219
$entityManager->dropTable($entityClass, $prefix);
220220
} catch (\RuntimeException) {

0 commit comments

Comments
 (0)