clearml-server/server/database/query.py

64 lines
2.0 KiB
Python
Raw Normal View History

2019-06-10 21:24:35 +00:00
import copy
import re
from mongoengine import Q
from mongoengine.queryset.visitor import QueryCompilerVisitor, SimplificationVisitor, QCombination
class RegexWrapper(object):
def __init__(self, pattern, flags=None):
super(RegexWrapper, self).__init__()
self.pattern = pattern
self.flags = flags
@property
def regex(self):
return re.compile(self.pattern, self.flags if self.flags is not None else 0)
class RegexMixin(object):
def to_query(self, document):
query = self.accept(SimplificationVisitor())
query = query.accept(RegexQueryCompilerVisitor(document))
return query
def _combine(self, other, operation):
"""Combine this node with another node into a QCombination
object.
"""
if getattr(other, 'empty', True):
return self
if self.empty:
return other
return RegexQCombination(operation, [self, other])
class RegexQCombination(RegexMixin, QCombination):
pass
class RegexQ(RegexMixin, Q):
pass
class RegexQueryCompilerVisitor(QueryCompilerVisitor):
"""
Improved mongoengine complied queries visitor class that supports compiled regex expressions as part of the query.
We need this class since mongoengine's Q (QNode) class uses copy.deepcopy() as part of the tree simplification
stage, which does not support re.compiled objects (since Python 2.5).
This class allows users to provide regex strings wrapped in QueryRegex instances, which are lazily evaluated to
to re.compile instances just before being visited for compilation (this is done after the simplification stage)
"""
def visit_query(self, query):
query = copy.deepcopy(query)
query.query = self._transform_query(query.query)
return super(RegexQueryCompilerVisitor, self).visit_query(query)
def _transform_query(self, query):
return {k: v.regex if isinstance(v, RegexWrapper) else v for k, v in query.items()}