Skip to content

Commit

Permalink
WIP pgsql compatibility
Browse files Browse the repository at this point in the history
Signed-off-by: Florian Steffens <florian.steffens@nextcloud.com>
  • Loading branch information
Florian Steffens committed Aug 7, 2023
1 parent 9cb373c commit bfe4321
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 36 deletions.
5 changes: 0 additions & 5 deletions lib/Db/ColumnTypes/DatetimeColumnQB.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@
namespace OCA\Tables\Db\ColumnTypes;

use OCP\DB\QueryBuilder\IQueryBuilder;
use Psr\Log\LoggerInterface;

class DatetimeColumnQB extends SuperColumnQB implements IColumnTypeQB {
protected LoggerInterface $logger;
protected int $platform;

public function passSearchValue(IQueryBuilder $qb, string $unformattedSearchValue, string $operator, string $searchValuePlaceHolder): void {
$qb->setParameter($searchValuePlaceHolder, $unformattedSearchValue, IQueryBuilder::PARAM_STR);


}
}
4 changes: 1 addition & 3 deletions lib/Db/ColumnTypes/NumberColumnQB.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
namespace OCA\Tables\Db\ColumnTypes;

use OCP\DB\QueryBuilder\IQueryBuilder;
use Psr\Log\LoggerInterface;

class NumberColumnQB extends SuperColumnQB implements IColumnTypeQB {
protected LoggerInterface $logger;
protected int $platform;

public function passSearchValue(IQueryBuilder $qb, string $unformattedSearchValue, string $operator, string $searchValuePlaceHolder): void {
// TODO can we filter for float values?
$qb->setParameter($searchValuePlaceHolder, $unformattedSearchValue, IQueryBuilder::PARAM_INT);
}
}
4 changes: 0 additions & 4 deletions lib/Db/ColumnTypes/SelectionColumnQB.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@

namespace OCA\Tables\Db\ColumnTypes;

use Psr\Log\LoggerInterface;

class SelectionColumnQB extends SuperColumnQB implements IColumnTypeQB {
protected LoggerInterface $logger;
protected int $platform;
}
42 changes: 31 additions & 11 deletions lib/Db/ColumnTypes/SuperColumnQB.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,16 @@ public function setPlatform(int $platform) {
}

public function formatCellValue(string $unformattedValue): string {
return 'JSON_UNQUOTE(LOWER('.$unformattedValue.'))';
if ($this->platform === self::DB_PLATFORM_PGSQL) {
return 'LOWER('.$unformattedValue.')';
} elseif ($this->platform === self::DB_PLATFORM_SQLITE) {
// TODO DB BE SQLITE
return '';
} else { // mariadb / mysql
return 'JSON_UNQUOTE(LOWER(' . $unformattedValue . '))';
}
}

public function passSearchValue(IQueryBuilder $qb, string $unformattedSearchValue, string $operator, string $searchValuePlaceHolder): void {
$lowerCaseSearchValue = strtolower($unformattedSearchValue);
switch ($operator) {
Expand All @@ -47,12 +55,17 @@ public function passSearchValue(IQueryBuilder $qb, string $unformattedSearchValu
* @return string
* @throws InternalError
*/
private function buildSQLString(string $operator, string $formattedCellValue, string $searchValuePlaceHolder) : string {
private function buildSqlFilterString(string $operator, string $formattedCellValue, string $searchValuePlaceHolder, string $columnPlaceHolder = null) : string {
if ($this->platform === self::DB_PLATFORM_PGSQL) {
return '';
return "id IN (".
"SELECT id ".
"FROM oc_tables_rows, json_array_elements(data) as t1 ".
"WHERE CAST(t1->>'columnId' AS int) = :".$columnPlaceHolder." AND ".$formattedCellValue." LIKE :".$searchValuePlaceHolder.
")";
} elseif ($this->platform === self::DB_PLATFORM_SQLITE) {
// TODO DB BE SQLITE
return '';
} else {
} else { // mariadb / mysql
switch ($operator) {
case 'begins-with':
case 'ends-with':
Expand All @@ -77,7 +90,14 @@ private function buildSQLString(string $operator, string $formattedCellValue, st
}

private function getFormattedDataCellValue(string $columnPlaceHolder): string {
$cellValue = 'JSON_EXTRACT(data, CONCAT( JSON_UNQUOTE(JSON_SEARCH(JSON_EXTRACT(data, \'$[*].columnId\'), \'one\', :'.$columnPlaceHolder.')), \'.value\'))';
if ($this->platform === self::DB_PLATFORM_PGSQL) {
$cellValue = 't1 ->> \'value\'';
} elseif ($this->platform === self::DB_PLATFORM_SQLITE) {
// TODO DB BE SQLITE
} else {
$cellValue = 'JSON_EXTRACT(data, CONCAT( JSON_UNQUOTE(JSON_SEARCH(JSON_EXTRACT(data, \'$[*].columnId\'), \'one\', :'.$columnPlaceHolder.')), \'.value\'))';
}

return $this->formatCellValue($cellValue);
}

Expand Down Expand Up @@ -105,17 +125,17 @@ private function getFormattedMetaDataCellValue(int $metaId): string {
* @throws InternalError
*/
public function addWhereFilterExpression(IQueryBuilder $qb, array $filter, string $filterId): IQueryFunction {
$searchValuePlaceHolder = 'searchValue'.$filterId;
$columnPlaceHolder = 'column'.$filterId;
if($filter['columnId'] >= 0) {
$searchValuePlaceHolder = 'searchValue'.$filterId; // qb parameter binding name
$columnPlaceHolder = 'column'.$filterId; // qb parameter binding name
if($filter['columnId'] >= 0) { // negative ids for meta data columns
$qb->setParameter($columnPlaceHolder, $filter['columnId'], IQueryBuilder::PARAM_INT);
$formattedCellValue = $this->getFormattedDataCellValue($columnPlaceHolder);
$formattedCellValue = $this->getFormattedDataCellValue($columnPlaceHolder); // as sql string
} else {
$formattedCellValue = $this->getFormattedMetaDataCellValue($filter['columnId']);
$formattedCellValue = $this->getFormattedMetaDataCellValue($filter['columnId']); // as sql string
}

$this->passSearchValue($qb, $filter['value'], $filter['operator'], $searchValuePlaceHolder);
return $qb->createFunction($this->buildSQLString($filter['operator'], $formattedCellValue, $searchValuePlaceHolder));
return $qb->createFunction($this->buildSqlFilterString($filter['operator'], $formattedCellValue, $searchValuePlaceHolder, $columnPlaceHolder));

}

Expand Down
4 changes: 0 additions & 4 deletions lib/Db/ColumnTypes/TextColumnQB.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@

namespace OCA\Tables\Db\ColumnTypes;

use Psr\Log\LoggerInterface;

class TextColumnQB extends SuperColumnQB implements IColumnTypeQB {
protected LoggerInterface $logger;
protected int $platform;
}
20 changes: 11 additions & 9 deletions lib/Db/RowMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,14 @@ public function find(int $id): Row {

private function buildFilterByColumnType($qb, array $filter, string $filterId): string {
try {
$qbClassName = 'OCA\Tables\Db\ColumnTypes\\';
$columnQbClassName = 'OCA\Tables\Db\ColumnTypes\\';
$type = explode("-", $filter['columnType'])[0];

$qbClassName .= ucfirst($type).'ColumnQB';
$columnQbClassName .= ucfirst($type).'ColumnQB';

$qbClass = Server::get($qbClassName);
return $qbClass->addWhereFilterExpression($qb, $filter, $filterId);
/** @var IColumnTypeQB $columnQb */
$columnQb = Server::get($columnQbClassName);
return $columnQb->addWhereFilterExpression($qb, $filter, $filterId);
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
$this->logger->debug('Column type query builder class not found');
}
Expand Down Expand Up @@ -213,12 +214,13 @@ public function getRowIdsOfView(View $view, $userId): array {
}


private function addFilterToQuery(IQueryBuilder $qb, View $view, array $neededColumns, string $userId): void {
private function addFilterToQuery(IQueryBuilder $qb, View $view, array $neededColumnTypes, string $userId): void {
$enrichedFilters = $view->getFilterArray();
if (count($enrichedFilters) > 0) {
foreach ($enrichedFilters as &$filterGroup) {
foreach ($filterGroup as &$filter) {
$filter['columnType'] = $neededColumns[$filter['columnId']];
$filter['columnType'] = $neededColumnTypes[$filter['columnId']];
// TODO move resolution for magic fields to service layer
if(str_starts_with($filter['value'], '@')) {
$filter['value'] = $this->resolveSearchValue($filter['value'], $userId);
}
Expand Down Expand Up @@ -271,17 +273,17 @@ public function findAllByView(View $view, string $userId, ?int $limit = null, ?i


$neededColumnIds = $this->getAllColumnIdsFromView($view);
$neededColumns = $this->columnMapper->getColumnTypes($neededColumnIds);
$neededColumnsTypes = $this->columnMapper->getColumnTypes($neededColumnIds);

// Filter

$this->addFilterToQuery($qb, $view, $neededColumns, $userId);
$this->addFilterToQuery($qb, $view, $neededColumnsTypes, $userId);

// Sorting

$enrichedSort = $view->getSortArray();
foreach ($enrichedSort as &$sort) {
$sort['columnType'] = $neededColumns[$sort['columnId']];
$sort['columnType'] = $neededColumnsTypes[$sort['columnId']];
}
$this->addOrderByRules($qb, $enrichedSort);

Expand Down

0 comments on commit bfe4321

Please sign in to comment.