Skip to content

Commit 8405f29

Browse files
committed
feat: add relation lookup column type (post-merge fixes)
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
1 parent afb8e87 commit 8405f29

2 files changed

Lines changed: 68 additions & 112 deletions

File tree

lib/Db/Row2Mapper.php

Lines changed: 60 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,16 @@ class Row2Mapper {
3333

3434
private const DB_CHUNK_SIZE = 1_000;
3535

36-
private RowSleeveMapper $rowSleeveMapper;
37-
private ?string $userId;
38-
private IDBConnection $db;
39-
private LoggerInterface $logger;
40-
protected UserHelper $userHelper;
41-
protected ColumnMapper $columnMapper;
42-
43-
private ColumnsHelper $columnsHelper;
44-
45-
public function __construct(?string $userId, IDBConnection $db, LoggerInterface $logger, UserHelper $userHelper, RowSleeveMapper $rowSleeveMapper, ColumnsHelper $columnsHelper, ColumnMapper $columnMapper) {
46-
$this->rowSleeveMapper = $rowSleeveMapper;
47-
$this->userId = $userId;
48-
$this->db = $db;
49-
$this->logger = $logger;
50-
$this->userHelper = $userHelper;
51-
$this->columnsHelper = $columnsHelper;
52-
$this->columnMapper = $columnMapper;
53-
}
36+
public function __construct(
37+
private ?string $userId,
38+
private IDBConnection $db,
39+
private LoggerInterface $logger,
40+
protected UserHelper $userHelper,
41+
private RowSleeveMapper $rowSleeveMapper,
42+
private ColumnsHelper $columnsHelper,
43+
protected ColumnMapper $columnMapper,
44+
) {
45+
}
5446

5547
/**
5648
* @param Row2 $row
@@ -71,7 +63,7 @@ public function delete(Row2 $row): Row2 {
7163
} catch (Throwable $e) {
7264
$this->db->rollBack();
7365
$this->logger->error($e->getMessage(), ['exception' => $e]);
74-
throw new Exception(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
66+
throw new Exception(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
7567
}
7668

7769
return $row;
@@ -95,12 +87,12 @@ public function find(int $id, array $columns): Row2 {
9587
if (count($rows) === 0) {
9688
$e = new Exception('Wanted row not found.');
9789
$this->logger->error($e->getMessage(), ['exception' => $e]);
98-
throw new NotFoundError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
90+
throw new NotFoundError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
9991
}
10092

10193
$e = new Exception('Too many results for one wanted row.');
10294
$this->logger->error($e->getMessage(), ['exception' => $e]);
103-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
95+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
10496
}
10597

10698
/**
@@ -111,7 +103,7 @@ public function findNextId(int $offsetId = -1): ?int {
111103
$rowSleeve = $this->rowSleeveMapper->findNext($offsetId);
112104
} catch (MultipleObjectsReturnedException|Exception $e) {
113105
$this->logger->error($e->getMessage(), ['exception' => $e]);
114-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
106+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
115107
} catch (DoesNotExistException) {
116108
return null;
117109
}
@@ -162,10 +154,10 @@ private function getWantedRowIds(string $userId, int $tableId, ?array $filter =
162154
$result = $this->db->executeQuery($qb->getSQL(), $qb->getParameters(), $qb->getParameterTypes());
163155
} catch (Exception $e) {
164156
$this->logger->error($e->getMessage(), ['exception' => $e]);
165-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage(), );
157+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage(), );
166158
}
167159

168-
return array_map(fn (array $item) => $item['id'], $result->fetchAll());
160+
return array_map(fn (array $item) => $item['id'], $result->fetchAllAssociative());
169161
}
170162

171163
/**
@@ -192,7 +184,7 @@ public function findAll(array $showColumnIds, int $tableId, ?int $limit = null,
192184
return $this->sortRowsByIds($rows, $wantedRowIdsArray);
193185
} catch (DoesNotExistException $e) {
194186
$this->logger->error($e->getMessage(), ['exception' => $e]);
195-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
187+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
196188
}
197189
}
198190

@@ -266,14 +258,14 @@ private function getRowsChunk(array $rowIds, array $columnIds): array {
266258
$result = $qb->executeQuery();
267259
} catch (Exception $e) {
268260
$this->logger->error($e->getMessage(), ['exception' => $e]);
269-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage(), );
261+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage(), );
270262
}
271263

272264
try {
273265
$sleeves = $this->rowSleeveMapper->findMultiple($rowIds);
274266
} catch (Exception $e) {
275267
$this->logger->error($e->getMessage(), ['exception' => $e]);
276-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
268+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
277269
}
278270

279271
return $this->parseEntities($result, $sleeves);
@@ -414,7 +406,7 @@ private function getFilter(IQueryBuilder $qb, array $filterGroup): array {
414406
} else {
415407
$e = new Exception('Needed column (' . $columnId . ') not found.');
416408
$this->logger->error($e->getMessage(), ['exception' => $e]);
417-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
409+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
418410
}
419411
$filterExpressions[] = $sql;
420412
}
@@ -430,7 +422,7 @@ private function getFilterExpression(IQueryBuilder $qb, Column $column, string $
430422
$value = $this->getCellMapper($column)->filterValueToQueryParam($column, $value);
431423
} catch (DoesNotExistException $e) {
432424
$this->logger->error('Cannot filter, because the column does not exist', ['exception' => $e]);
433-
throw new InternalError(get_class($this) . '::' . __FUNCTION__ . ': Cannot filter, because the column does not exist');
425+
throw new InternalError(static::class . '::' . __FUNCTION__ . ': Cannot filter, because the column does not exist');
434426
}
435427

436428
// We try to match the requested value against the default before building the query
@@ -607,23 +599,14 @@ private function getMetaFilterExpression(IQueryBuilder $qb, int $columnId, strin
607599
$qb2->select('id');
608600
$qb2->from('tables_row_sleeves');
609601

610-
switch ($columnId) {
611-
case Column::TYPE_META_ID:
612-
$qb2->where($this->getSqlOperator($operator, $qb, 'id', (int)$value, IQueryBuilder::PARAM_INT));
613-
break;
614-
case Column::TYPE_META_CREATED_BY:
615-
$qb2->where($this->getSqlOperator($operator, $qb, 'created_by', $value, IQueryBuilder::PARAM_STR));
616-
break;
617-
case Column::TYPE_META_CREATED_AT:
618-
$qb2->where($this->getSqlOperator($operator, $qb, 'created_at', new DateTimeImmutable($value), IQueryBuilder::PARAM_DATE));
619-
break;
620-
case Column::TYPE_META_UPDATED_BY:
621-
$qb2->where($this->getSqlOperator($operator, $qb, 'last_edit_by', $value, IQueryBuilder::PARAM_STR));
622-
break;
623-
case Column::TYPE_META_UPDATED_AT:
624-
$qb2->where($this->getSqlOperator($operator, $qb, 'last_edit_at', new DateTimeImmutable($value), IQueryBuilder::PARAM_DATE));
625-
break;
626-
}
602+
match ($columnId) {
603+
Column::TYPE_META_ID => $qb2->where($this->getSqlOperator($operator, $qb, 'id', (int)$value, IQueryBuilder::PARAM_INT)),
604+
Column::TYPE_META_CREATED_BY => $qb2->where($this->getSqlOperator($operator, $qb, 'created_by', $value, IQueryBuilder::PARAM_STR)),
605+
Column::TYPE_META_CREATED_AT => $qb2->where($this->getSqlOperator($operator, $qb, 'created_at', new DateTimeImmutable($value), IQueryBuilder::PARAM_DATE)),
606+
Column::TYPE_META_UPDATED_BY => $qb2->where($this->getSqlOperator($operator, $qb, 'last_edit_by', $value, IQueryBuilder::PARAM_STR)),
607+
Column::TYPE_META_UPDATED_AT => $qb2->where($this->getSqlOperator($operator, $qb, 'last_edit_at', new DateTimeImmutable($value), IQueryBuilder::PARAM_DATE)),
608+
default => $qb2,
609+
};
627610
return $qb2;
628611
}
629612

@@ -637,32 +620,20 @@ private function getMetaFilterExpression(IQueryBuilder $qb, int $columnId, strin
637620
* @throws InternalError
638621
*/
639622
private function getSqlOperator(string $operator, IQueryBuilder $qb, string $columnName, $value, $paramType): string {
640-
switch ($operator) {
641-
case 'begins-with':
642-
return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType));
643-
case 'ends-with':
644-
return $qb->expr()->like($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType));
645-
case 'contains':
646-
return $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
647-
case 'does-not-contain':
648-
return $qb->expr()->notLike($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType));
649-
case 'is-equal':
650-
return $qb->expr()->eq($columnName, $qb->createNamedParameter($value, $paramType));
651-
case 'is-not-equal':
652-
return $qb->expr()->neq($columnName, $qb->createNamedParameter($value, $paramType));
653-
case 'is-greater-than':
654-
return $qb->expr()->gt($columnName, $qb->createNamedParameter($value, $paramType));
655-
case 'is-greater-than-or-equal':
656-
return $qb->expr()->gte($columnName, $qb->createNamedParameter($value, $paramType));
657-
case 'is-lower-than':
658-
return $qb->expr()->lt($columnName, $qb->createNamedParameter($value, $paramType));
659-
case 'is-lower-than-or-equal':
660-
return $qb->expr()->lte($columnName, $qb->createNamedParameter($value, $paramType));
661-
case 'is-empty':
662-
return $qb->expr()->isNull($columnName);
663-
default:
664-
throw new InternalError('Operator ' . $operator . ' is not supported.');
665-
}
623+
return match ($operator) {
624+
'begins-with' => $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value), $paramType)),
625+
'ends-with' => $qb->expr()->like($columnName, $qb->createNamedParameter($this->db->escapeLikeParameter($value) . '%', $paramType)),
626+
'contains' => $qb->expr()->like($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType)),
627+
'does-not-contain' => $qb->expr()->notLike($columnName, $qb->createNamedParameter('%' . $this->db->escapeLikeParameter($value) . '%', $paramType)),
628+
'is-equal' => $qb->expr()->eq($columnName, $qb->createNamedParameter($value, $paramType)),
629+
'is-not-equal' => $qb->expr()->neq($columnName, $qb->createNamedParameter($value, $paramType)),
630+
'is-greater-than' => $qb->expr()->gt($columnName, $qb->createNamedParameter($value, $paramType)),
631+
'is-greater-than-or-equal' => $qb->expr()->gte($columnName, $qb->createNamedParameter($value, $paramType)),
632+
'is-lower-than' => $qb->expr()->lt($columnName, $qb->createNamedParameter($value, $paramType)),
633+
'is-lower-than-or-equal' => $qb->expr()->lte($columnName, $qb->createNamedParameter($value, $paramType)),
634+
'is-empty' => $qb->expr()->isNull($columnName),
635+
default => throw new InternalError('Operator ' . $operator . ' is not supported.'),
636+
};
666637
}
667638

668639
/**
@@ -688,16 +659,14 @@ private function parseEntities(IResult $result, array $sleeves): array {
688659
$keyToRowId = [];
689660
$cellMapperCache = [];
690661

691-
while ($rowData = $result->fetch()) {
662+
while ($rowData = $result->fetchAssociative()) {
692663
if (!isset($rowData['row_id'], $rows[$rowData['row_id']])) {
693664
break;
694665
}
695666

696667
$column = $this->columnMapper->find($rowData['column_id']);
697668
$columnType = $column->getType();
698-
if (!isset($cellMapperCache[$columnType])) {
699-
$cellMapperCache[$columnType] = $this->getCellMapperFromType($columnType);
700-
}
669+
$cellMapperCache[$columnType] ??= $this->getCellMapperFromType($columnType);
701670
$value = $cellMapperCache[$columnType]->formatRowData($column, $rowData);
702671
$compositeKey = (string)$rowData['row_id'] . ',' . (string)$rowData['column_id'];
703672
if ($cellMapperCache[$columnType]->hasMultipleValues()) {
@@ -778,7 +747,7 @@ public function update(Row2 $row, ?string $userId = null): Row2 {
778747
$this->rowSleeveMapper->update($sleeve);
779748
} catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) {
780749
$this->logger->error($e->getMessage(), ['exception' => $e]);
781-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
750+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
782751
}
783752

784753
$this->columnMapper->preloadColumns(array_column($changedCells, 'columnId'));
@@ -845,7 +814,7 @@ private function insertCell(int $rowId, int $columnId, $value, ?string $lastEdit
845814
$column = $this->columnMapper->find($columnId);
846815
} catch (DoesNotExistException $e) {
847816
$this->logger->error('Can not insert cell, because the given column-id is not known', ['exception' => $e]);
848-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
817+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
849818
}
850819

851820
if ($this->isVirtualColumn($column->getType())) {
@@ -910,7 +879,7 @@ private function insertOrUpdateCell(int $rowId, int $columnId, $value): void {
910879
$cellMapper = $this->getCellMapper($column);
911880
try {
912881
if ($cellMapper->hasMultipleValues()) {
913-
$this->atomic(function () use ($cellMapper, $rowId, $columnId, $value) {
882+
$this->atomic(function () use ($cellMapper, $rowId, $columnId, $value): void {
914883
// For a usergroup field with mutiple values, each is inserted as a new cell
915884
// we need to delete all previous cells for this row and column, otherwise we get duplicates
916885
$cellMapper->deleteAllForColumnAndRow($columnId, $rowId);
@@ -924,7 +893,7 @@ private function insertOrUpdateCell(int $rowId, int $columnId, $value): void {
924893
$this->insertCell($rowId, $columnId, $value);
925894
} catch (MultipleObjectsReturnedException|Exception $e) {
926895
$this->logger->error($e->getMessage(), ['exception' => $e]);
927-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
896+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
928897
}
929898
}
930899

@@ -942,7 +911,7 @@ private function getCellMapperFromType(string $columnType): RowCellMapperSuper {
942911
return Server::get($cellMapperClassName);
943912
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
944913
$this->logger->error($e->getMessage(), ['exception' => $e]);
945-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
914+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
946915
}
947916
}
948917

@@ -964,7 +933,7 @@ public function deleteDataForColumn(Column $column): void {
964933
$this->getCellMapper($column)->deleteAllForColumn($column->getId());
965934
} catch (Exception $e) {
966935
$this->logger->error($e->getMessage(), ['exception' => $e]);
967-
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
936+
throw new InternalError(static::class . ' - ' . __FUNCTION__ . ': ' . $e->getMessage());
968937
}
969938
}
970939

@@ -1012,26 +981,15 @@ public function countRowsForView(View $view, string $userId): int {
1012981

1013982
private function getFormattedDefaultValue(Column $column) {
1014983
$defaultValue = null;
1015-
switch ($column->getType()) {
1016-
case Column::TYPE_SELECTION:
1017-
$defaultValue = $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getSelectionDefault());
1018-
break;
1019-
case Column::TYPE_DATETIME:
1020-
$defaultValue = $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getDatetimeDefault());
1021-
break;
1022-
case Column::TYPE_NUMBER:
1023-
$defaultValue = $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getNumberDefault());
1024-
break;
1025-
case Column::TYPE_TEXT:
1026-
$defaultValue = $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getTextDefault());
1027-
break;
1028-
case Column::TYPE_USERGROUP:
1029-
$defaultValue = $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getUsergroupDefault());
1030-
break;
1031-
case Column::TYPE_RELATION_LOOKUP:
1032-
$defaultValue = null;
1033-
break;
1034-
}
984+
$defaultValue = match ($column->getType()) {
985+
Column::TYPE_SELECTION => $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getSelectionDefault()),
986+
Column::TYPE_DATETIME => $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getDatetimeDefault()),
987+
Column::TYPE_NUMBER => $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getNumberDefault()),
988+
Column::TYPE_TEXT => $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getTextDefault()),
989+
Column::TYPE_USERGROUP => $this->getCellMapper($column)->filterValueToQueryParam($column, $column->getUsergroupDefault()),
990+
Column::TYPE_RELATION_LOOKUP => null,
991+
default => $defaultValue,
992+
};
1035993
return $defaultValue;
1036994
}
1037995

lib/Service/RelationService.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ class RelationService {
3030
private array $cacheRelationData = [];
3131

3232
public function __construct(
33-
private ColumnMapper $columnMapper,
34-
private ViewMapper $viewMapper,
35-
private Row2Mapper $row2Mapper,
36-
private ColumnService $columnService,
37-
private IUserSession $userSession,
38-
private LoggerInterface $logger,
33+
private readonly ColumnMapper $columnMapper,
34+
private readonly ViewMapper $viewMapper,
35+
private readonly Row2Mapper $row2Mapper,
36+
private readonly ColumnService $columnService,
37+
private readonly IUserSession $userSession,
38+
private readonly LoggerInterface $logger,
3939
) {
4040
}
4141

@@ -126,9 +126,7 @@ private function fetchRelationColumns(array $columns): array {
126126
$settings = $column->getCustomSettingsObject(RelationSettings::class);
127127
$targetKey = $this->buildRelationCacheKey($settings->relationType, $settings->targetId, $settings->labelColumn);
128128

129-
if (!isset($fetchedTargets[$targetKey])) {
130-
$fetchedTargets[$targetKey] = $this->fetchRelationValuesForTarget($column);
131-
}
129+
$fetchedTargets[$targetKey] ??= $this->fetchRelationValuesForTarget($column);
132130

133131
$result[$column->getId()] = $fetchedTargets[$targetKey];
134132
} catch (\InvalidArgumentException $e) {
@@ -199,7 +197,7 @@ private function fetchRelationValuesForTarget(Column $column): array {
199197
try {
200198
$targetColumn = $this->columnMapper->find($settings->labelColumn);
201199
$rows = $this->fetchRowsForTarget($settings, [$settings->labelColumn]);
202-
} catch (DoesNotExistException $e) {
200+
} catch (DoesNotExistException) {
203201
$this->cacheRelationData[$cacheKey] = [];
204202
return [];
205203
}

0 commit comments

Comments
 (0)