Skip to content
Open
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
13 changes: 3 additions & 10 deletions lib/Analytics/AnalyticsDatasource.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,9 @@ public function getTemplate(): array {
// get all tables and subsequent views
foreach ($tables as $table) {
$tableString = $tableString . $table->getId() . '-' . $table->getTitle() . '/';
// get all views per table
try {
$views = $this->viewService->findAll($this->tableService->find($table->getId()), $this->userId);
foreach ($views as $view) {
// concatenate the option-string. The format is tableId:viewId-title
$tableString = $tableString . $table->getId() . ':' . $view->getId() . '-' . $view->getTitle() . '/';
}
} catch (PermissionError) {
// this is a shared table without shared views;
continue;
foreach ($table->getViews() ?? [] as $view) {
// concatenate the option-string. The format is tableId:viewId-title
$tableString = $tableString . $table->getId() . ':' . $view->getId() . '-' . $view->getTitle() . '/';
}
}

Expand Down
5 changes: 3 additions & 2 deletions lib/Controller/Api1Controller.php
Comment thread
Koc marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,12 @@ public function deleteTable(int $tableId): DataResponse {
#[NoAdminRequired]
#[NoCSRFRequired]
#[CORS]
#[RequirePermission(permission: Application::PERMISSION_READ, type: Application::NODE_TYPE_TABLE, idParam: 'tableId')]
#[RequirePermission(permission: Application::PERMISSION_MANAGE, type: Application::NODE_TYPE_TABLE, idParam: 'tableId')]
#[OpenAPI(scope: OpenAPI::SCOPE_DEFAULT)]
public function indexViews(int $tableId): DataResponse {
try {
return new DataResponse($this->viewService->formatViews($this->viewService->findAll($this->tableService->find($tableId))));
$table = $this->tableService->find($tableId);
return new DataResponse($this->viewService->formatViews($table->getViews() ?? []));
Comment thread
Koc marked this conversation as resolved.
Resolved
} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: ' . $e->getMessage(), ['exception' => $e]);
$message = ['message' => $e->getMessage()];
Expand Down
37 changes: 23 additions & 14 deletions lib/Db/ColumnMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

/** @template-extends QBMapper<Column> */
class ColumnMapper extends QBMapper {
private const DB_CHUNK_SIZE = 1_000;

protected string $table = 'tables_columns';
private readonly CappedMemoryCache $cacheColumn;

Expand Down Expand Up @@ -166,24 +168,31 @@ public function getColumnTypes(array $neededColumnIds): array {
}

/**
* @param int $tableId
* @return int
* @param int[] $tableIds
* @return array<int, int>
*/
public function countColumns(int $tableId): int {
public function countColumnsForTables(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$qb = $this->db->getQueryBuilder();
$qb->select($qb->func()->count('*', 'counter'));
$qb->from($this->table);
$qb->where(
$qb->expr()->eq('table_id', $qb->createNamedParameter($tableId))
);
$qb->select('table_id', $qb->func()->count('*', 'counter'))
->from($this->table)
->where($qb->expr()->in('table_id', $qb->createParameter('tableIds')))
->groupBy('table_id');

try {
$result = $this->findOneQuery($qb);
return (int)$result['counter'];
} catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Returning 0.');
return 0;
$counts = array_fill_keys($tableIds, 0);
foreach (array_chunk($tableIds, self::DB_CHUNK_SIZE - 1) as $tableIdsChunk) {
$qb->setParameter('tableIds', $tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
$result = $qb->executeQuery();
while ($row = $result->fetchAssociative()) {
$counts[(int)$row['table_id']] = (int)$row['counter'];
}
$result->closeCursor();
}

return $counts;
}

/**
Expand Down
7 changes: 6 additions & 1 deletion lib/Db/Row2Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -1015,8 +1015,13 @@ public function deleteAllForTable(int $tableId, array $columns): void {
}
}

/**
* @param int $tableId
* @return int
*/
public function countRowsForTable(int $tableId): int {
return $this->rowSleeveMapper->countRows($tableId);
$counts = $this->rowSleeveMapper->countRowsByTableIds([$tableId]);
return $counts[$tableId] ?? 0;
}

/**
Expand Down
21 changes: 0 additions & 21 deletions lib/Db/RowSleeveMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,6 @@ public function deleteAllForTable(int $tableId): int {
return $qb->executeStatement();
}

/**
* @param int $tableId
* @return int
*/
public function countRows(int $tableId): int {
$qb = $this->db->getQueryBuilder();
$qb->select($qb->func()->count('*', 'counter'));
$qb->from($this->table, 't1');
$qb->where(
$qb->expr()->eq('table_id', $qb->createNamedParameter($tableId))
);

try {
$result = $this->findOneQuery($qb);
return (int)$result['counter'];
} catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) {
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Will return 0.');
return 0;
}
}

/**
* @param int[] $tableIds
* @return array<int, int>
Expand Down
89 changes: 78 additions & 11 deletions lib/Db/ShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

/** @template-extends QBMapper<Share> */
class ShareMapper extends QBMapper {
private const DB_CHUNK_SIZE = 1_000;

protected string $table = 'tables_shares';

public function __construct(
Expand Down Expand Up @@ -99,17 +101,18 @@ public function findAllSharesFor(string $nodeType, array $receivers, string $use
return [];
}

$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
->where($qb->expr()->in('receiver', $qb->createParameter('receivers')))
->andWhere($qb->expr()->neq('sender', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType)))
->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter($receiverType)));

$chunks = [];
// deduct extra parameters (sender, node type, receiver type)
foreach (array_chunk($receivers, 1000 - 3) as $receiversChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
->where($qb->expr()->in('receiver', $qb->createNamedParameter($receiversChunk, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($qb->expr()->neq('sender', $qb->createNamedParameter($userId)))
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType)))
->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter($receiverType)));

foreach (array_chunk($receivers, self::DB_CHUNK_SIZE - 3) as $receiversChunk) {
$qb->setParameter('receivers', $receiversChunk, IQueryBuilder::PARAM_STR_ARRAY);
$chunks[] = $this->findEntities($qb);
}

Expand All @@ -119,12 +122,11 @@ public function findAllSharesFor(string $nodeType, array $receivers, string $use
/**
* @param string $nodeType
* @param int $nodeId
* @param string $sender
* @param array<string> $excluded receiver types to exclude from results
* @return Share[]
* @throws Exception
*/
public function findAllSharesForNode(string $nodeType, int $nodeId, string $sender = '', array $excluded = []): array {
public function findAllSharesForNode(string $nodeType, int $nodeId, array $excluded = []): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
Expand All @@ -138,6 +140,71 @@ public function findAllSharesForNode(string $nodeType, int $nodeId, string $send
return $this->findEntities($qb);
}

/**
* @param string $nodeType
* @param int[] $nodeIds
* @param array<string> $excluded receiver types to exclude from results
* @return Share[]
* @throws Exception
*/
public function findAllSharesForNodes(string $nodeType, array $nodeIds, array $excluded = []): array {
if (empty($nodeIds)) {
return [];
}

$extraParams = 2;
if (!empty($excluded)) {
$extraParams++;
}

$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->table)
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter($nodeType, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->in('node_id', $qb->createParameter('nodeIds')));

if (!empty($excluded)) {
$qb->andWhere($qb->expr()->notIn('receiver_type', $qb->createNamedParameter($excluded, IQueryBuilder::PARAM_STR_ARRAY)));
}

$chunks = [];
foreach (array_chunk($nodeIds, self::DB_CHUNK_SIZE - $extraParams) as $nodeIdsChunk) {
$qb->setParameter('nodeIds', $nodeIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
$chunks[] = $this->findEntities($qb);
}

return array_merge(...$chunks);
}

/**
* @param int[] $tableIds
* @return int[]
*/
public function findTableIdsWithLinkShares(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$qb = $this->db->getQueryBuilder();
$qb->selectDistinct('node_id')
->from($this->table)
->andWhere($qb->expr()->eq('node_type', $qb->createNamedParameter('table', IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter(ShareReceiverType::LINK, IQueryBuilder::PARAM_STR)))
->andWhere($qb->expr()->in('node_id', $qb->createParameter('tableIds')));

$linkTableIds = [];
foreach (array_chunk($tableIds, self::DB_CHUNK_SIZE - 2) as $tableIdsChunk) {
$qb->setParameter('tableIds', $tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
$result = $qb->executeQuery();
while ($row = $result->fetchAssociative()) {
$linkTableIds[] = (int)$row['node_id'];
}
$result->closeCursor();
}

return $linkTableIds;
}

/**
* @param string $nodeType
* @param int $nodeId
Expand Down
42 changes: 36 additions & 6 deletions lib/Db/ViewMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ public function findMany(array $ids): array {
}

$missing = array_keys($missing);
foreach (array_chunk($missing, 1000) as $missingChunk) {
$qb = $this->db->getQueryBuilder();
$qb->select('v.*', 't.ownership')
->from($this->table, 'v')
->leftJoin('v', 'tables_tables', 't', 't.id = v.table_id')
->where($qb->expr()->in('v.id', $qb->createNamedParameter($missingChunk, IQueryBuilder::PARAM_INT_ARRAY)));
$qb = $this->db->getQueryBuilder();
$qb->select('v.*', 't.ownership')
->from($this->table, 'v')
->leftJoin('v', 'tables_tables', 't', 't.id = v.table_id')
->where($qb->expr()->in('v.id', $qb->createParameter('viewIds')));

foreach (array_chunk($missing, self::DB_CHUNK_SIZE) as $missingChunk) {
$qb->setParameter('viewIds', $missingChunk, IQueryBuilder::PARAM_INT_ARRAY);
foreach ($this->findEntities($qb) as $entity) {
$id = $entity->getId();
$this->cache[(string)$id] = $entity;
Expand Down Expand Up @@ -127,6 +128,8 @@ public function insert(Entity $entity): View {
}

/**
* @deprecated Use {@link findAllByTableIds} instead
*
* @return View[]
* @throws Exception
*/
Expand All @@ -146,6 +149,33 @@ public function findAll(?int $tableId = null): array {
return $this->findEntities($qb);
}

/**
* @param int[] $tableIds
* @return View[]
* @throws Exception
*/
public function findAllByTableIds(array $tableIds): array {
if (empty($tableIds)) {
return [];
}

$qb = $this->db->getQueryBuilder();
$qb->select('v.*', 't.ownership')
->from($this->table, 'v')
->innerJoin('v', 'tables_tables', 't', 't.id = v.table_id')
->where($qb->expr()->in('v.table_id', $qb->createParameter('tableIds')))
->addOrderBy('v.sidebar_order', 'ASC')
->addOrderBy('v.id', 'ASC');

$chunks = [];
foreach (array_chunk($tableIds, self::DB_CHUNK_SIZE - 1) as $tableIdsChunk) {
$qb->setParameter('tableIds', $tableIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
$chunks[] = $this->findEntities($qb);
}

return array_merge(...$chunks);
}

/**
* @return View[]
* @throws Exception
Expand Down
17 changes: 17 additions & 0 deletions lib/Helper/UserHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ public function getUserDisplayName(string $userId): string {
}
}

/**
* @param string[] $userIds
* @return array<string, null|string>
*/
public function getUsersDisplayNames(array $userIds): array {
$displayNames = [];
foreach (array_unique($userIds) as $userId) {
if ($userId === '' || $userId === null) {
$displayNames[$userId] = $userId;
continue;
}
$displayName = $this->userManager->getDisplayName($userId);
$displayNames[$userId] = $displayName ?: $userId;
}
return $displayNames;
}

/**
* @throws InternalError
*/
Expand Down
24 changes: 16 additions & 8 deletions lib/Service/ColumnService.php
Original file line number Diff line number Diff line change
Expand Up @@ -785,16 +785,24 @@ public function findOrCreateColumnsByTitleForTableAsArray(?int $tableId, ?int $v
}

/**
* @param int $tableId
* @return int
* @throws PermissionError
* @param int[] $tableIds
* @param string|null $userId
* @return array<int, int>
*/
public function getColumnsCount(int $tableId): int {
if ($this->permissionsService->canReadColumnsByTableId($tableId)) {
return $this->mapper->countColumns($tableId);
} else {
throw new PermissionError('no read access for counting to table id = ' . $tableId);
public function getColumnsCountForTables(array $tableIds, ?string $userId = null): array {
$userId = $this->permissionsService->preCheckUserId($userId);
$readableTableIds = array_values(array_filter(
$tableIds,
fn (int $tableId): bool => $this->permissionsService->canReadColumnsByTableId($tableId, $userId),
));

$counts = $this->mapper->countColumnsForTables($readableTableIds);

$result = [];
foreach ($tableIds as $tableId) {
$result[$tableId] = $counts[$tableId] ?? 0;
}
return $result;
}

/**
Expand Down
Loading
Loading