mirror of
https://github.com/clearml/clearml-server
synced 2025-06-26 23:15:47 +00:00
Support active users in projects
This commit is contained in:
@@ -637,6 +637,35 @@ class GetMixin(PropsMixin):
|
||||
|
||||
return qs
|
||||
|
||||
@classmethod
|
||||
def _get_queries_for_order_field(
|
||||
cls, query: Q, order_field: str
|
||||
) -> Union[None, Tuple[Q, Q]]:
|
||||
"""
|
||||
In case the order_field is one of the cls fields and the sorting is ascending
|
||||
then return the tuple of 2 queries:
|
||||
1. original query with not empty constraint on the order_by field
|
||||
2. original query with empty constraint on the order_by field
|
||||
"""
|
||||
if not order_field or order_field.startswith("-") or "[" in order_field:
|
||||
return
|
||||
|
||||
mongo_field_name = order_field.replace(".", "__")
|
||||
mongo_field = first(
|
||||
v for k, v in cls.get_all_fields_with_instance() if k == mongo_field_name
|
||||
)
|
||||
if not mongo_field:
|
||||
return
|
||||
|
||||
params = {}
|
||||
if isinstance(mongo_field, ListField):
|
||||
params["is_list"] = True
|
||||
elif isinstance(mongo_field, StringField):
|
||||
params["empty_value"] = ""
|
||||
non_empty = query & field_exists(mongo_field_name, **params)
|
||||
empty = query & field_does_not_exist(mongo_field_name, **params)
|
||||
return non_empty, empty
|
||||
|
||||
@classmethod
|
||||
def _get_many_override_none_ordering(
|
||||
cls: Union[Document, "GetMixin"],
|
||||
@@ -675,21 +704,9 @@ class GetMixin(PropsMixin):
|
||||
order_field = first(
|
||||
field for field in order_by if not field.startswith("$")
|
||||
)
|
||||
if (
|
||||
order_field
|
||||
and not order_field.startswith("-")
|
||||
and "[" not in order_field
|
||||
):
|
||||
params = {}
|
||||
mongo_field = order_field.replace(".", "__")
|
||||
if mongo_field in cls.get_field_names_for_type(of_type=ListField):
|
||||
params["is_list"] = True
|
||||
elif mongo_field in cls.get_field_names_for_type(of_type=StringField):
|
||||
params["empty_value"] = ""
|
||||
non_empty = query & field_exists(mongo_field, **params)
|
||||
empty = query & field_does_not_exist(mongo_field, **params)
|
||||
query_sets = [cls.objects(non_empty), cls.objects(empty)]
|
||||
|
||||
res = cls._get_queries_for_order_field(query, order_field)
|
||||
if res:
|
||||
query_sets = [cls.objects(q) for q in res]
|
||||
query_sets = [qs.order_by(*order_by) for qs in query_sets]
|
||||
if order_field:
|
||||
collation_override = first(
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from collections import OrderedDict, defaultdict
|
||||
from itertools import chain
|
||||
from collections import OrderedDict
|
||||
from operator import attrgetter
|
||||
from threading import Lock
|
||||
from typing import Sequence
|
||||
|
||||
import six
|
||||
from mongoengine import EmbeddedDocumentField, EmbeddedDocumentListField
|
||||
from mongoengine.base import get_document, BaseField
|
||||
from mongoengine.base import get_document
|
||||
|
||||
from apiserver.database.fields import (
|
||||
LengthRangeEmbeddedDocumentListField,
|
||||
@@ -21,7 +20,7 @@ class PropsMixin(object):
|
||||
__cached_reference_fields = None
|
||||
__cached_exclude_fields = None
|
||||
__cached_fields_with_instance = None
|
||||
__cached_field_names_per_type = None
|
||||
__cached_all_fields_with_instance = None
|
||||
|
||||
__cached_dpath_computed_fields_lock = Lock()
|
||||
__cached_dpath_computed_fields = None
|
||||
@@ -33,37 +32,12 @@ class PropsMixin(object):
|
||||
return cls.__cached_fields
|
||||
|
||||
@classmethod
|
||||
def get_field_names_for_type(cls, of_type=BaseField):
|
||||
"""
|
||||
Return field names per type including subfields
|
||||
The fields of derived types are also returned
|
||||
"""
|
||||
assert issubclass(of_type, BaseField)
|
||||
if cls.__cached_field_names_per_type is None:
|
||||
fields = defaultdict(list)
|
||||
for name, field in get_fields(cls, return_instance=True, subfields=True):
|
||||
fields[type(field)].append(name)
|
||||
for type_ in fields:
|
||||
fields[type_].extend(
|
||||
chain.from_iterable(
|
||||
fields[other_type]
|
||||
for other_type in fields
|
||||
if other_type != type_ and issubclass(other_type, type_)
|
||||
)
|
||||
)
|
||||
cls.__cached_field_names_per_type = fields
|
||||
|
||||
if of_type not in cls.__cached_field_names_per_type:
|
||||
names = list(
|
||||
chain.from_iterable(
|
||||
field_names
|
||||
for type_, field_names in cls.__cached_field_names_per_type.items()
|
||||
if issubclass(type_, of_type)
|
||||
)
|
||||
def get_all_fields_with_instance(cls):
|
||||
if cls.__cached_all_fields_with_instance is None:
|
||||
cls.__cached_all_fields_with_instance = get_fields(
|
||||
cls, return_instance=True, subfields=True
|
||||
)
|
||||
cls.__cached_field_names_per_type[of_type] = names
|
||||
|
||||
return cls.__cached_field_names_per_type[of_type]
|
||||
return cls.__cached_all_fields_with_instance
|
||||
|
||||
@classmethod
|
||||
def get_fields_with_instance(cls, doc_cls):
|
||||
|
||||
Reference in New Issue
Block a user