Skip to content
Snippets Groups Projects
Verified Commit c98e4866 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

WIP: many-to-many

parent e0c0869e
No related branches found
No related tags found
No related merge requests found
...@@ -110,6 +110,18 @@ class DefaultCaosDBClientDelegate: ...@@ -110,6 +110,18 @@ class DefaultCaosDBClientDelegate:
self._caosdb.configure_connection(**kwargs) 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): def _get_filter_clause(self, fil):
LOGGER.debug("enter _get_filter_clause(%s)", fil) LOGGER.debug("enter _get_filter_clause(%s)", fil)
if not "type" in fil: if not "type" in fil:
...@@ -120,13 +132,12 @@ class DefaultCaosDBClientDelegate: ...@@ -120,13 +132,12 @@ class DefaultCaosDBClientDelegate:
components = [self._get_filter_clause(comps) for comps in components = [self._get_filter_clause(comps) for comps in
fil["elements"]] fil["elements"]]
return " AND".join(components) 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"]: if filter_type in ["reference", "back_reference"]:
ref = fil return self._get_reference_clause(**fil)
result = " " + ref["str"]
if "sub" in ref:
subquery = self._get_filter_clause(ref["sub"])
result += " WITH (" + subquery + ")"
return result
if filter_type == "in": if filter_type == "in":
p = fil["p"] p = fil["p"]
values = fil["v"] values = fil["v"]
......
...@@ -8,17 +8,3 @@ class DjaosdbManager(Manager): ...@@ -8,17 +8,3 @@ class DjaosdbManager(Manager):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._db = "caosdb" 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()
...@@ -162,22 +162,18 @@ class JoinConverter(Converter): ...@@ -162,22 +162,18 @@ class JoinConverter(Converter):
def _reference(self): def _reference(self):
if self.left_column == "id": if self.left_column == "id":
backref = f"{self.right_table} AS {self.right_column}"
return { return {
"type": "back_reference", "type": "back_reference",
"p": self.right_column, "p": self.right_column,
"v": self.right_table, "v": self.right_table,
"negation": False, "negation": False,
"str": f"IS REFERENCED BY {backref}"
} }
elif self.right_column == "id": elif self.right_column == "id":
ref = f"{self.right_table} AS {self.left_column}"
return { return {
"type": "reference", "type": "reference",
"p": self.left_column, "p": self.left_column,
"v": self.right_table, "v": self.right_table,
"negation": False, "negation": False,
"str": f"REFERENCES {ref}",
} }
return None return None
...@@ -396,19 +392,21 @@ class NestedInQueryConverter(Converter): ...@@ -396,19 +392,21 @@ class NestedInQueryConverter(Converter):
def __init__(self, token, *args): def __init__(self, token, *args):
self._token = token self._token = token
self._in_query: O['query_module.SelectQuery'] = None self._in_query: O['query_module.SelectQuery'] = None
self.ignore = False
super().__init__(*args) super().__init__(*args)
def parse(self): def parse(self):
from .query import SelectQuery from .query import SelectQuery
self._in_query = SelectQuery( self._in_query = SelectQuery(
self.query.db, self.query.connection,
self.query.connection_properties,
sqlparse(self._token.value[1:-1])[0], sqlparse(self._token.value[1:-1])[0],
self.query.params self.query.params
) )
def to_mongo(self): def to_mongo(self):
if self.ignore:
return []
pipeline = [ pipeline = [
{ {
'$lookup': { '$lookup': {
......
...@@ -109,8 +109,20 @@ class _InNotInOp(_BinaryOp): ...@@ -109,8 +109,20 @@ class _InNotInOp(_BinaryOp):
def to_mongo(self): def to_mongo(self):
raise NotImplementedError 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): def _to_mongo(self, op):
if self.query.nested_query is not None: 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 { return {
'$expr': { '$expr': {
op: ['$' + self._field, '$_nested_in'] op: ['$' + self._field, '$_nested_in']
...@@ -170,20 +182,14 @@ class LikeOp(_BinaryOp): ...@@ -170,20 +182,14 @@ class LikeOp(_BinaryOp):
if not isinstance(to_match, str): if not isinstance(to_match, str):
raise SQLDecodeError raise SQLDecodeError
to_match = to_match.replace('%', '.*') to_match = to_match.replace('%', '*')
self._regex = '^' + to_match + '$' self._regex = to_match
def to_mongo(self): 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): class IsOp(_BinaryOp):
...@@ -322,9 +328,15 @@ class _AndOrOp(_Op): ...@@ -322,9 +328,15 @@ class _AndOrOp(_Op):
else: else:
oper = 'or' 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, return {"type": oper,
"elements": docs} "elements": elems}
class AndOp(_AndOrOp): class AndOp(_AndOrOp):
...@@ -384,7 +396,7 @@ class _StatementParser: ...@@ -384,7 +396,7 @@ class _StatementParser:
op = LikeOp(**kw) op = LikeOp(**kw)
elif tok.match(tokens.Keyword, 'iLIKE'): elif tok.match(tokens.Keyword, 'iLIKE'):
op = iLikeOp(**kw) op = LikeOp(**kw)
elif tok.match(tokens.Keyword, 'BETWEEN'): elif tok.match(tokens.Keyword, 'BETWEEN'):
op = BetweenOp(**kw) op = BetweenOp(**kw)
...@@ -411,6 +423,8 @@ class _StatementParser: ...@@ -411,6 +423,8 @@ class _StatementParser:
elif isinstance(tok, Identifier): elif isinstance(tok, Identifier):
pass pass
elif tok.match(tokens.Whitespace, r"\s", True):
pass
else: else:
raise SQLDecodeError raise SQLDecodeError
...@@ -533,6 +547,8 @@ class CmpOp(_Op): ...@@ -533,6 +547,8 @@ class CmpOp(_Op):
ref = self._identifier.table ref = self._identifier.table
field = self._identifier.column field = self._identifier.column
if field.endswith("_id"):
field = field[:-3]
result = {"type": "pov", result = {"type": "pov",
"negation": self.is_negated, "negation": self.is_negated,
"p": field, "p": field,
......
...@@ -258,12 +258,14 @@ class SelectQuery(DQLQuery): ...@@ -258,12 +258,14 @@ class SelectQuery(DQLQuery):
if self.joins: if self.joins:
joins = [join.to_mongo() for join in 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: if self.where:
where = self.where.to_mongo() where = self.where.to_mongo()
if self.nested_query:
nested = self.nested_query.to_mongo()
if nested:
aggregation["nested"] = nested
if self.groupby: if self.groupby:
aggregation["groupby"] = self.groupby.to_mongo() aggregation["groupby"] = self.groupby.to_mongo()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment