diff --git a/djaosdb/caosdb_client.py b/djaosdb/caosdb_client.py index d297b24cc4405e8a9b5121db587b6bfdd2fe019d..6982eb13592857fc8cb7f1cda9becfaaf4d83218 100644 --- a/djaosdb/caosdb_client.py +++ b/djaosdb/caosdb_client.py @@ -110,6 +110,18 @@ class DefaultCaosDBClientDelegate: self._caosdb.configure_connection(**kwargs) + def _get_reference_clause(self, type, p, v, negation, sub=None): + result = (f" REFERENCES {v}" + if type == "reference" + else f" IS REFERENCED BY {v}") + # todo use v as well + + if sub is not None: + subquery = self._get_filter_clause(sub) + result += " WITH (" + subquery + ")" + return result + + def _get_filter_clause(self, fil): LOGGER.debug("enter _get_filter_clause(%s)", fil) if not "type" in fil: @@ -120,13 +132,12 @@ class DefaultCaosDBClientDelegate: components = [self._get_filter_clause(comps) for comps in fil["elements"]] return " AND".join(components) + if filter_type == "or": + components = [self._get_filter_clause(comps) for comps in + fil["elements"]] + return " OR".join(components) if filter_type in ["reference", "back_reference"]: - ref = fil - result = " " + ref["str"] - if "sub" in ref: - subquery = self._get_filter_clause(ref["sub"]) - result += " WITH (" + subquery + ")" - return result + return self._get_reference_clause(**fil) if filter_type == "in": p = fil["p"] values = fil["v"] diff --git a/djaosdb/models/manager.py b/djaosdb/models/manager.py index 6ece6ee9cac42413feed24220a9ec314a7aa9c61..bf0255f8247c38dd3ece518b5a72801e5446b5fd 100644 --- a/djaosdb/models/manager.py +++ b/djaosdb/models/manager.py @@ -8,17 +8,3 @@ class DjaosdbManager(Manager): def __init__(self): super().__init__() self._db = "caosdb" - - @property - def db(self): - db = super().db() - return db - - def get_queryset(self): - qs = super().get_queryset() - return qs - - def db_manager(self): - return super().db_manager() - - diff --git a/djaosdb/sql2mongo/converters.py b/djaosdb/sql2mongo/converters.py index e06c13f333d1f67445c2c4277843e3f2e48357f7..744a80a7cb15640d7a0877cdb3404711ca00d811 100644 --- a/djaosdb/sql2mongo/converters.py +++ b/djaosdb/sql2mongo/converters.py @@ -162,22 +162,18 @@ class JoinConverter(Converter): def _reference(self): if self.left_column == "id": - backref = f"{self.right_table} AS {self.right_column}" return { "type": "back_reference", "p": self.right_column, "v": self.right_table, "negation": False, - "str": f"IS REFERENCED BY {backref}" } elif self.right_column == "id": - ref = f"{self.right_table} AS {self.left_column}" return { "type": "reference", "p": self.left_column, "v": self.right_table, "negation": False, - "str": f"REFERENCES {ref}", } return None @@ -396,19 +392,21 @@ class NestedInQueryConverter(Converter): def __init__(self, token, *args): self._token = token self._in_query: O['query_module.SelectQuery'] = None + self.ignore = False super().__init__(*args) def parse(self): from .query import SelectQuery self._in_query = SelectQuery( - self.query.db, - self.query.connection_properties, + self.query.connection, sqlparse(self._token.value[1:-1])[0], self.query.params ) def to_mongo(self): + if self.ignore: + return [] pipeline = [ { '$lookup': { diff --git a/djaosdb/sql2mongo/operators.py b/djaosdb/sql2mongo/operators.py index 3f427df30269a26fe29307d553c18a0bc6030ef4..59d37fd5935cf50033d678d3fc355f8811e6e309 100644 --- a/djaosdb/sql2mongo/operators.py +++ b/djaosdb/sql2mongo/operators.py @@ -109,8 +109,20 @@ class _InNotInOp(_BinaryOp): def to_mongo(self): raise NotImplementedError + def _to_caosdb(self, op, nested_select): + if op=="$in" and nested_select.left_table == self._field: + pipeline = nested_select._make_pipeline() + if pipeline == {"projection": ["id"]}: + return {} + def _to_mongo(self, op): if self.query.nested_query is not None: + caosdb_filter = self._to_caosdb(op, + self.query.nested_query._in_query) + if caosdb_filter is not None: + self.query.nested_query.ignore = True + return caosdb_filter + return { '$expr': { op: ['$' + self._field, '$_nested_in'] @@ -170,20 +182,14 @@ class LikeOp(_BinaryOp): if not isinstance(to_match, str): raise SQLDecodeError - to_match = to_match.replace('%', '.*') - self._regex = '^' + to_match + '$' + to_match = to_match.replace('%', '*') + self._regex = to_match def to_mongo(self): - return {self._field: {'$regex': self._regex}} + return {"type": "pov", "p": self._field, "o": " LIKE ", "v": self._regex, + "negation": False} -class iLikeOp(LikeOp): - def to_mongo(self): - return {self._field: { - '$regex': self._regex, - '$options': 'i' - }} - class IsOp(_BinaryOp): @@ -322,9 +328,15 @@ class _AndOrOp(_Op): else: oper = 'or' - docs = [itm.to_mongo() for itm in self._acc] + elems = [elem for elem in [itm.to_mongo() for itm in self._acc] if + elem] + if len(elems) == 1: + return elems[0] + elif len(elems) == 0: + return None + return {"type": oper, - "elements": docs} + "elements": elems} class AndOp(_AndOrOp): @@ -384,7 +396,7 @@ class _StatementParser: op = LikeOp(**kw) elif tok.match(tokens.Keyword, 'iLIKE'): - op = iLikeOp(**kw) + op = LikeOp(**kw) elif tok.match(tokens.Keyword, 'BETWEEN'): op = BetweenOp(**kw) @@ -411,6 +423,8 @@ class _StatementParser: elif isinstance(tok, Identifier): pass + elif tok.match(tokens.Whitespace, r"\s", True): + pass else: raise SQLDecodeError @@ -533,6 +547,8 @@ class CmpOp(_Op): ref = self._identifier.table field = self._identifier.column + if field.endswith("_id"): + field = field[:-3] result = {"type": "pov", "negation": self.is_negated, "p": field, diff --git a/djaosdb/sql2mongo/query.py b/djaosdb/sql2mongo/query.py index 514af27630a2ca81f5f5337a4a937713ff9c79c1..2bb7785e718a717c37f250cd92342b585fb7d9fc 100644 --- a/djaosdb/sql2mongo/query.py +++ b/djaosdb/sql2mongo/query.py @@ -258,12 +258,14 @@ class SelectQuery(DQLQuery): if self.joins: joins = [join.to_mongo() for join in self.joins] - if self.nested_query: - aggregation["nested"] = self.nested_query.to_mongo() - if self.where: where = self.where.to_mongo() + if self.nested_query: + nested = self.nested_query.to_mongo() + if nested: + aggregation["nested"] = nested + if self.groupby: aggregation["groupby"] = self.groupby.to_mongo()