Skip to content

Commit d53ae56

Browse files
committed
feat(dbal): Add missing stuff in DBAL wrapper
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
1 parent c849c3b commit d53ae56

13 files changed

Lines changed: 357 additions & 52 deletions

File tree

apps/dav/lib/Migration/Version1034Date20250605132605.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
6060
'notnull' => true,
6161
'length' => 255,
6262
]);
63+
/** @psalm-suppress InvalidArgument legacy column */
6364
$federatedCalendarsTable->addColumn('remote_Url', Types::STRING, [
6465
'notnull' => true,
6566
'length' => 255,

lib/composer/composer/autoload_classmap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@
373373
'OCP\\DB\\QueryBuilder\\ITypedQueryBuilder' => $baseDir . '/lib/public/DB/QueryBuilder/ITypedQueryBuilder.php',
374374
'OCP\\DB\\QueryBuilder\\Sharded\\IShardMapper' => $baseDir . '/lib/public/DB/QueryBuilder/Sharded/IShardMapper.php',
375375
'OCP\\DB\\Schema\\IColumn' => $baseDir . '/lib/public/DB/Schema/IColumn.php',
376+
'OCP\\DB\\Schema\\IForeignKeyConstraint' => $baseDir . '/lib/public/DB/Schema/IForeignKeyConstraint.php',
376377
'OCP\\DB\\Schema\\IIndex' => $baseDir . '/lib/public/DB/Schema/IIndex.php',
377378
'OCP\\DB\\Schema\\ITable' => $baseDir . '/lib/public/DB/Schema/ITable.php',
378379
'OCP\\DB\\Schema\\IType' => $baseDir . '/lib/public/DB/Schema/IType.php',
@@ -1785,6 +1786,7 @@
17851786
'OC\\DB\\SQLiteSessionInit' => $baseDir . '/lib/private/DB/SQLiteSessionInit.php',
17861787
'OC\\DB\\SchemaWrapper' => $baseDir . '/lib/private/DB/SchemaWrapper.php',
17871788
'OC\\DB\\Schema\\Column' => $baseDir . '/lib/private/DB/Schema/Column.php',
1789+
'OC\\DB\\Schema\\ForeignKeyConstraint' => $baseDir . '/lib/private/DB/Schema/ForeignKeyConstraint.php',
17881790
'OC\\DB\\Schema\\Index' => $baseDir . '/lib/private/DB/Schema/Index.php',
17891791
'OC\\DB\\Schema\\Table' => $baseDir . '/lib/private/DB/Schema/Table.php',
17901792
'OC\\DB\\Schema\\Type' => $baseDir . '/lib/private/DB/Schema/Type.php',

lib/composer/composer/autoload_static.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
414414
'OCP\\DB\\QueryBuilder\\ITypedQueryBuilder' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ITypedQueryBuilder.php',
415415
'OCP\\DB\\QueryBuilder\\Sharded\\IShardMapper' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/Sharded/IShardMapper.php',
416416
'OCP\\DB\\Schema\\IColumn' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IColumn.php',
417+
'OCP\\DB\\Schema\\IForeignKeyConstraint' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IForeignKeyConstraint.php',
417418
'OCP\\DB\\Schema\\IIndex' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IIndex.php',
418419
'OCP\\DB\\Schema\\ITable' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/ITable.php',
419420
'OCP\\DB\\Schema\\IType' => __DIR__ . '/../../..' . '/lib/public/DB/Schema/IType.php',
@@ -1826,6 +1827,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
18261827
'OC\\DB\\SQLiteSessionInit' => __DIR__ . '/../../..' . '/lib/private/DB/SQLiteSessionInit.php',
18271828
'OC\\DB\\SchemaWrapper' => __DIR__ . '/../../..' . '/lib/private/DB/SchemaWrapper.php',
18281829
'OC\\DB\\Schema\\Column' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Column.php',
1830+
'OC\\DB\\Schema\\ForeignKeyConstraint' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/ForeignKeyConstraint.php',
18291831
'OC\\DB\\Schema\\Index' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Index.php',
18301832
'OC\\DB\\Schema\\Table' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Table.php',
18311833
'OC\\DB\\Schema\\Type' => __DIR__ . '/../../..' . '/lib/private/DB/Schema/Type.php',

lib/private/DB/Schema/Column.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Doctrine\DBAL\Schema\Column as DBALColumn;
1313
use Doctrine\DBAL\Schema\SchemaException as DBALSchemaException;
1414
use Doctrine\DBAL\Types\Type as DBALType;
15+
use OCP\DB\Schema\ColumnType;
1516
use OCP\DB\Schema\IColumn;
1617
use OCP\DB\Schema\IType;
1718
use OCP\DB\Schema\SchemaException;
@@ -33,11 +34,15 @@ public function getWrappedColumn(): DBALColumn {
3334
}
3435

3536
#[\Override]
36-
public function setType(string|IType|DBALType $type): self {
37+
public function setType(string|IType|DBALType|ColumnType $type): self {
3738
if ($type instanceof IType) {
3839
$type = $type->getName();
3940
}
4041

42+
if ($type instanceof ColumnType) {
43+
$type = $type->value;
44+
}
45+
4146
$this->column->setType($type instanceof DBALType ? $type : DBALType::getType($type));
4247

4348
return $this;
@@ -97,6 +102,11 @@ public function getType(): IType {
97102
return new Type($this->column->getType());
98103
}
99104

105+
#[\Override]
106+
public function getColumnType(): ColumnType {
107+
return ColumnType::from(DBALType::lookupName($this->column->getType()));
108+
}
109+
100110
#[\Override]
101111
public function getLength(): ?int {
102112
return $this->column->getLength();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH
7+
* SPDX-FileContributor: Carl Schwan
8+
* SPDX-License-Identifier: AGPL-3.0-or-later
9+
*/
10+
11+
namespace OC\DB\Schema;
12+
13+
use Doctrine\DBAL\Schema\ForeignKeyConstraint as DBALForeignKeyConstraint;
14+
use OCP\DB\Schema\IForeignKeyConstraint;
15+
use Override;
16+
17+
class ForeignKeyConstraint implements IForeignKeyConstraint {
18+
19+
public function __construct(
20+
private readonly DBALForeignKeyConstraint $keyConstraint,
21+
) {
22+
}
23+
24+
#[Override]
25+
public function getName(): string {
26+
/** @var non-empty-string $value */
27+
$value = $this->keyConstraint->getName();
28+
return $value;
29+
}
30+
}

lib/private/DB/Schema/Index.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public function isSimpleIndex(): bool {
5353
return $this->index->isSimpleIndex();
5454
}
5555

56+
#[\Override]
57+
public function hasColumnAtPosition(string $name, int $position = 0): bool {
58+
return $this->index->hasColumnAtPosition($name, $position);
59+
}
60+
5661
/**
5762
* Forwards any method not declared on IIndex to the wrapped Doctrine
5863
* DBAL index, e.g. mutators like `addFlag()` or `removeFlag()` that are

lib/private/DB/Schema/Table.php

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
namespace OC\DB\Schema;
1111

1212
use Doctrine\DBAL\Schema\Column as DBALColumn;
13+
use Doctrine\DBAL\Schema\ForeignKeyConstraint as DBALForeignKeyConstraint;
1314
use Doctrine\DBAL\Schema\Index as DBALIndex;
1415
use Doctrine\DBAL\Schema\SchemaException as DBALSchemaException;
1516
use Doctrine\DBAL\Schema\Table as DBALTable;
17+
use Doctrine\DBAL\Types\Type as DBALType;
18+
use OCP\DB\Schema\ColumnType;
1619
use OCP\DB\Schema\IColumn;
20+
use OCP\DB\Schema\IForeignKeyConstraint;
1721
use OCP\DB\Schema\IIndex;
1822
use OCP\DB\Schema\ITable;
1923
use OCP\DB\Schema\SchemaException;
@@ -36,7 +40,9 @@ public function getWrappedTable(): DBALTable {
3640

3741
#[\Override]
3842
public function getName(): string {
39-
return $this->table->getName();
43+
/** @var non-empty-lowercase-string $name */
44+
$name = $this->table->getName();
45+
return $name;
4046
}
4147

4248
#[\Override]
@@ -134,8 +140,11 @@ public function renameIndex(string $oldName, ?string $newName = null): self {
134140
}
135141

136142
#[\Override]
137-
public function addColumn(string $name, string $typeName, array $options = []): IColumn {
143+
public function addColumn(string $name, string|ColumnType $typeName, array $options = []): IColumn {
138144
try {
145+
if ($typeName instanceof ColumnType) {
146+
$typeName = $typeName->value;
147+
}
139148
return new Column($this->table->addColumn($name, $typeName, $options));
140149
} catch (DBALSchemaException $e) {
141150
throw new SchemaException($e->getMessage(), $e->getCode(), $e);
@@ -145,6 +154,14 @@ public function addColumn(string $name, string $typeName, array $options = []):
145154
#[\Override]
146155
public function modifyColumn(string $name, array $options): self {
147156
try {
157+
if (isset($options['type'])) {
158+
if ($options['type'] instanceof ColumnType) {
159+
$options['type'] = $options['type']->value;
160+
}
161+
if (is_string($options['type'])) {
162+
$options['type'] = DBALType::getType($options['type']);
163+
}
164+
}
148165
$this->table->modifyColumn($name, $options);
149166
} catch (DBALSchemaException $e) {
150167
throw new SchemaException($e->getMessage(), $e->getCode(), $e);
@@ -210,8 +227,8 @@ public function __call(string $name, array $arguments): mixed {
210227
}
211228

212229
#[\Override]
213-
public function hasColumn(string $string): bool {
214-
return $this->table->hasColumn($string);
230+
public function hasColumn(string $name): bool {
231+
return $this->table->hasColumn($name);
215232
}
216233

217234
#[\Override]
@@ -238,4 +255,12 @@ public function getIndexes(): array {
238255
$this->table->getIndexes(),
239256
));
240257
}
258+
259+
#[\Override]
260+
public function getForeignKeys(): array {
261+
return array_values(array_map(
262+
static fn (DBALForeignKeyConstraint $keyConstraint): IForeignKeyConstraint => new ForeignKeyConstraint($keyConstraint),
263+
$this->table->getForeignKeys(),
264+
));
265+
}
241266
}

lib/public/AppFramework/Db/Entity.php

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
namespace OCP\AppFramework\Db;
1010

11+
use OCP\DB\Schema\ColumnType;
1112
use OCP\DB\Types;
1213
use function lcfirst;
1314
use function substr;
@@ -23,8 +24,8 @@ abstract class Entity {
2324
public $id;
2425
/** @var array<string, true> $_updatedFields */
2526
private array $_updatedFields = [];
26-
/** @var array<string, Types::*> $_fieldTypes */
27-
protected array $_fieldTypes = ['id' => 'integer'];
27+
/** @var array<string, ColumnType> $_fieldTypes */
28+
protected array $_fieldTypes = ['id' => ColumnType::Integer];
2829

2930
/**
3031
* Simple alternative constructor for building entities from a request
@@ -66,7 +67,7 @@ public static function fromRow(array $row): static {
6667
* @since 7.0.0
6768
*/
6869
public function getFieldTypes(): array {
69-
return $this->_fieldTypes;
70+
return array_map(fn (ColumnType $type) => $type->value, $this->_fieldTypes);
7071
}
7172

7273
/**
@@ -98,7 +99,7 @@ protected function setter(string $name, array $args): void {
9899
// if type definition exists, cast to correct type
99100
if ($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) {
100101
$type = $this->_fieldTypes[$name];
101-
if ($type === Types::BLOB) {
102+
if ($type === ColumnType::Blob) {
102103
// (B)LOB is treated as string when we read from the DB
103104
if (is_resource($args[0])) {
104105
$args[0] = stream_get_contents($args[0]);
@@ -107,32 +108,32 @@ protected function setter(string $name, array $args): void {
107108
}
108109

109110
switch ($type) {
110-
case Types::BIGINT:
111-
case Types::SMALLINT:
111+
case ColumnType::Bigint:
112+
case ColumnType::Smallint:
112113
settype($args[0], Types::INTEGER);
113114
break;
114-
case Types::BINARY:
115-
case Types::DECIMAL:
116-
case Types::TEXT:
115+
case ColumnType::Binary:
116+
case ColumnType::Decimal:
117+
case ColumnType::Text:
117118
settype($args[0], Types::STRING);
118119
break;
119-
case Types::TIME:
120-
case Types::DATE:
121-
case Types::DATETIME:
122-
case Types::DATETIME_TZ:
120+
case ColumnType::Time:
121+
case ColumnType::Date:
122+
case ColumnType::Datetime:
123+
case ColumnType::DatetimeTz:
123124
if (!$args[0] instanceof \DateTime) {
124125
$args[0] = new \DateTime($args[0]);
125126
}
126127
break;
127-
case Types::TIME_IMMUTABLE:
128-
case Types::DATE_IMMUTABLE:
129-
case Types::DATETIME_IMMUTABLE:
130-
case Types::DATETIME_TZ_IMMUTABLE:
128+
case ColumnType::TimeImmutable:
129+
case ColumnType::DateImmutable:
130+
case ColumnType::DatetimeImmutable:
131+
case ColumnType::DatetimeTzImmutable:
131132
if (!$args[0] instanceof \DateTimeImmutable) {
132133
$args[0] = new \DateTimeImmutable($args[0]);
133134
}
134135
break;
135-
case Types::JSON:
136+
case ColumnType::Json:
136137
if (!is_array($args[0])) {
137138
$args[0] = json_decode($args[0], true);
138139
}
@@ -187,7 +188,7 @@ public function __call(string $methodName, array $args) {
187188
protected function isGetterForBoolProperty(string $methodName): bool {
188189
if (str_starts_with($methodName, 'is')) {
189190
$fieldName = lcfirst(substr($methodName, 2));
190-
return isset($this->_fieldTypes[$fieldName]) && str_starts_with($this->_fieldTypes[$fieldName], 'bool');
191+
return isset($this->_fieldTypes[$fieldName]) && str_starts_with($this->_fieldTypes[$fieldName]->value, 'bool');
191192
}
192193
return false;
193194
}
@@ -258,23 +259,28 @@ public function getUpdatedFields(): array {
258259
* that value once its being returned from the database
259260
*
260261
* @param string $fieldName the name of the attribute
261-
* @param Types::* $type the type which will be used to match a cast
262+
* @param Types::*|ColumnType $type the type which will be used to match a cast
262263
* @since 31.0.0 Parameter $type is now restricted to {@see Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly.
264+
* @since 35.0.0 Parameter $type now prefers using one of the {@see ColumnType} enum values.
263265
* @since 7.0.0
264266
*/
265-
protected function addType(string $fieldName, string $type): void {
267+
protected function addType(string $fieldName, string|ColumnType $type): void {
266268
/** @psalm-suppress TypeDoesNotContainType */
267269
if (in_array($type, ['bool', 'double', 'int', 'array', 'object'], true)) {
268270
// Mapping legacy strings to the actual types
269271
$type = match ($type) {
270-
'int' => Types::INTEGER,
271-
'bool' => Types::BOOLEAN,
272-
'double' => Types::FLOAT,
272+
'int' => ColumnType::Integer,
273+
'bool' => ColumnType::Boolean,
274+
'double' => ColumnType::Float,
273275
'array',
274-
'object' => Types::STRING,
276+
'object' => ColumnType::String,
275277
};
276278
}
277279

280+
if (is_string($type)) {
281+
$type = ColumnType::from($type);
282+
}
283+
278284
$this->_fieldTypes[$fieldName] = $type;
279285
}
280286

0 commit comments

Comments
 (0)