Skip to content
Merged
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
14 changes: 14 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on: [push]
jobs:
test:
runs-on: ubuntu-latest
name: Nextcloud ${{ matrix.nextcloud }} - ${{ matrix.db.name }}
strategy:
matrix:
db:
Expand All @@ -12,6 +13,11 @@ jobs:
username: root
database: nextcloud
port: 3306
- name: pgsql
image: postgres:17.5
username: postgres
database: postgres
port: 5432
nextcloud: [31]
services:
db:
Expand Down Expand Up @@ -54,5 +60,13 @@ jobs:
run: >
php occ -n fulltextsearch:configure '{"search_platform": "OCA\\FullTextSearch_SQL\\Platform\\SQLPlatform"}'

# This can be removed as soon as https://github.com/nextcloud/fulltextsearch/pull/915 is merged.
- name: Fix test harness
run: >
sed -i \
-e "s/'document is a simple test'/'document is a'/" \
-e "s/document is a simple -test/document -test/" \
custom_apps/fulltextsearch/lib/Command/Test.php

- name: Run fulltextsearch test
run: php occ -n fulltextsearch:test --platform_delay 1
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Extension to the _Full text search_ app to communicate with the usual Nextcloud
<dependencies>
<nextcloud min-version="31" max-version="32"/>
<database>mysql</database>
<database>postgresql</database>
<database>pgsql</database>
</dependencies>

<fulltextsearch>
Expand Down
42 changes: 27 additions & 15 deletions lib/Db/IndexDocumentMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,43 @@ public function search(ISearchRequest $request, string $providerId, IDocumentAcc
);
}

$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('owner', $qb->createNamedParameter($access->getViewerId(), IQueryBuilder::PARAM_STR)),
'JSON_CONTAINS(access_users, ' . $qb->createNamedParameter(json_encode($access->getViewerId())) . ')',
'JSON_OVERLAPS(access_groups, ' . $qb->createNamedParameter(json_encode($access->getGroups())) . ')',
'JSON_OVERLAPS(access_circles, ' . $qb->createNamedParameter(json_encode($access->getCircles())) . ')',
)
);
$search = $qb->createNamedParameter($request->getSearch(), IQueryBuilder::PARAM_STR);
$viewerId = $qb->createNamedParameter($access->getViewerId(), IQueryBuilder::PARAM_STR);
$jsonViewerId = $qb->createNamedParameter(json_encode($access->getViewerId()), IQueryBuilder::PARAM_STR);
$jsonGroups = $qb->createNamedParameter(json_encode($access->getGroups()), IQueryBuilder::PARAM_STR);
$jsonCircles = $qb->createNamedParameter(json_encode($access->getCircles()), IQueryBuilder::PARAM_STR);

// TODO: Match tags, subtags, whatnot...

switch ($this->db->getDatabaseProvider()) {
case IDBConnection::PLATFORM_MYSQL:
$q = 'MATCH (content) AGAINST (:search IN BOOLEAN MODE)';
$qb->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('owner', $viewerId),
"JSON_CONTAINS(access_users, $jsonViewerId)",
"JSON_OVERLAPS(access_groups, $jsonGroups)",
"JSON_OVERLAPS(access_circles, $jsonCircles)",
)
);

$q = "MATCH (content) AGAINST ($search IN BOOLEAN MODE)";
$qb->andWhere($q)
->selectAlias($qb->createFunction($q), 'score');
break;

case IDBConnection::PLATFORM_POSTGRES:
$qb->andWhere('to_tsvector(content) @@ to_tsquery(:search)');
break;
case IDBConnection::PLATFORM_SQLITE:
break;
case IDBConnection::PLATFORM_ORACLE:
$qb
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('owner', $viewerId),
"access_users @> $jsonViewerId::jsonb",
"jsonb_exists_any(access_groups, JSON_QUERY($jsonGroups, '$' RETURNING text[]))",
"jsonb_exists_any(access_circles, JSON_QUERY($jsonCircles, '$' RETURNING text[]))",
)
)
->andWhere("to_tsvector(content) @@ websearch_to_tsquery($search)");
break;
}
$qb->setParameter('search', $request->getSearch());

return $this->findEntities($qb);
}
Expand Down
46 changes: 37 additions & 9 deletions lib/Migration/Version10000Date20250720000000.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

class Version10000Date20250720000000 extends SimpleMigrationStep {
public const TABLE = 'fts_documents';
private $collations = [
IDBConnection::PLATFORM_MYSQL => 'utf8mb4_unicode_ci',
IDBConnection::PLATFORM_POSTGRES => 'unicode',
];

public function __construct(
private IDBConnection $db
Expand Down Expand Up @@ -44,28 +48,52 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op
'notnull' => true
]);
$table->addColumn('access_users', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('access_circles', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('access_groups', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('access_links', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('tags', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('metadata', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('subtags', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('parts', Types::JSON, [
'notnull' => true
'notnull' => true,
'customSchemaOptions' => [
'jsonb' => true,
]
]);
$table->addColumn('link', Types::STRING, [
'notnull' => true
Expand All @@ -76,7 +104,7 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op
$table->addColumn('content', Types::TEXT, [
'notnull' => true,
'customSchemaOptions' => [
'collation' => 'utf8mb4_unicode_ci'
'collation' => $this->collations[$this->db->getDatabaseProvider()],
]
]);
$table->setPrimaryKey(['id']);
Expand Down