mirror of
https://github.com/quay/quay.git
synced 2025-04-18 10:44:06 +03:00
api: allow refining search with an organization (PROJQUAY-7244) (#2901)
This allows a more refined search than just the repo name. When two organizations contain the same name repo, e.g: org1/python and org2/python, you can now search via org1/python to get the specific result instead of both.
This commit is contained in:
parent
dde4dde03d
commit
4899ebd6c7
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
*.pyc
|
||||
venv
|
||||
.venv
|
||||
screenshots/screenshots/
|
||||
conf/stack
|
||||
*/node_modules
|
||||
|
@ -491,6 +491,9 @@ def _get_sorted_matching_repositories(
|
||||
"""
|
||||
select_fields = [Repository.id] if ids_only else [Repository, Namespace]
|
||||
|
||||
# Used to make sure that the join to the Namespace table only occurs once
|
||||
is_namespace_table_joined = False
|
||||
|
||||
if not lookup_value:
|
||||
# This is a generic listing of repositories. Simply return the sorted repositories based
|
||||
# on RepositorySearchScore.
|
||||
@ -505,15 +508,19 @@ def _get_sorted_matching_repositories(
|
||||
search_fields = set([SEARCH_FIELDS.description.name, SEARCH_FIELDS.name.name])
|
||||
|
||||
# Always search at least on name (init clause)
|
||||
clause = Repository.name.match(lookup_value)
|
||||
repo_name_value, user_name_value = lookup_value, None
|
||||
if "/" in lookup_value:
|
||||
user_name_value, repo_name_value = lookup_value.split("/", 1)
|
||||
|
||||
clause = Repository.name.match(repo_name_value)
|
||||
computed_score = RepositorySearchScore.score.alias("score")
|
||||
|
||||
# If the description field is in the search fields, then we need to compute a synthetic score
|
||||
# to discount the weight of the description more than the name.
|
||||
if SEARCH_FIELDS.description.name in search_fields:
|
||||
clause = Repository.description.match(lookup_value) | clause
|
||||
clause = Repository.description.match(repo_name_value) | clause
|
||||
cases = [
|
||||
(Repository.name.match(lookup_value), 100 * RepositorySearchScore.score),
|
||||
(Repository.name.match(repo_name_value), 100 * RepositorySearchScore.score),
|
||||
]
|
||||
computed_score = Case(None, cases, RepositorySearchScore.score).alias("score")
|
||||
|
||||
@ -526,16 +533,23 @@ def _get_sorted_matching_repositories(
|
||||
.order_by(SQL("score").desc(), RepositorySearchScore.id)
|
||||
)
|
||||
|
||||
# If an organization/user was found and it was not blank.
|
||||
if user_name_value is not None and user_name_value != "":
|
||||
query = (
|
||||
query.switch(Repository)
|
||||
.join(Namespace)
|
||||
.where(Namespace.username == user_name_value)
|
||||
)
|
||||
is_namespace_table_joined = True
|
||||
|
||||
if repo_kind is not None:
|
||||
query = query.where(Repository.kind == Repository.kind.get_id(repo_kind))
|
||||
|
||||
if not include_private:
|
||||
query = query.where(Repository.visibility == _basequery.get_public_repo_visibility())
|
||||
|
||||
if not ids_only:
|
||||
query = query.switch(Repository).join(
|
||||
Namespace, on=(Namespace.id == Repository.namespace_user)
|
||||
)
|
||||
if not ids_only and not is_namespace_table_joined:
|
||||
query = query.switch(Repository).join(Namespace)
|
||||
|
||||
return query
|
||||
|
||||
|
@ -64,6 +64,43 @@ def test_search_pagination(query, authed_username, initialized_db):
|
||||
assert repositories[1].id == next_repos[0].id
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
os.environ.get("TEST_DATABASE_URI", "").find("mysql") >= 0,
|
||||
reason="MySQL requires specialized indexing of newly created repos",
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"query,repo_count",
|
||||
[
|
||||
("somenewrepo", 3),
|
||||
("devtable/somenewrepo", 2),
|
||||
("devtable/", 2),
|
||||
("devtable/somenewrepo2", 1),
|
||||
("doesnotexist/somenewrepo", 0),
|
||||
("does/notexist/somenewrepo", 0),
|
||||
("/somenewrepo", 3),
|
||||
("repo/withslash", 0),
|
||||
("/repo/withslash", 1),
|
||||
],
|
||||
)
|
||||
def test_search_filtering_complex(query, repo_count, initialized_db):
|
||||
# Create some public repos
|
||||
repo1 = create_repository(
|
||||
"devtable", "somenewrepo", None, repo_kind="image", visibility="public"
|
||||
)
|
||||
repo2 = create_repository(
|
||||
"devtable", "somenewrepo2", None, repo_kind="image", visibility="public"
|
||||
)
|
||||
repo3 = create_repository(
|
||||
"freshuser", "somenewrepo", None, repo_kind="image", visibility="public"
|
||||
)
|
||||
repo4 = create_repository(
|
||||
"freshuser", "repo/withslash", None, repo_kind="image", visibility="public"
|
||||
)
|
||||
|
||||
repositories = get_filtered_matching_repositories(query, filter_username=None)
|
||||
assert len(repositories) == repo_count
|
||||
|
||||
|
||||
def test_get_estimated_repository_count(initialized_db):
|
||||
assert get_estimated_repository_count() >= Repository.select().count()
|
||||
|
||||
|
@ -139,7 +139,7 @@ Quay is covered by tests using various approaches. Read our [testing guide](/TES
|
||||
|
||||
## Contributing
|
||||
|
||||
How great that you want to contribute to Quay! Before starting make sure to check our [contributing guidelines](.github/CONTRIBUTE.md).
|
||||
How great that you want to contribute to Quay! Before starting make sure to check our [contributing guidelines](../.github/CONTRIBUTING.md).
|
||||
|
||||
# Using Quay
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user