def get_filtered_nodes(self, lookups, label=None, include_properties=None, limit=None, offset=None): # Using Cypher cypher = self.cypher if label: script = """start n=node:`%s`('label:%s') """ \ % (self.nidx.name, label) else: script = """start n=node:`%s`('label:*') """ \ % self.nidx.name where = None params = [] if lookups: wheres = q_lookup_builder() for lookup in lookups: if isinstance(lookup, q_lookup_builder): wheres &= lookup elif isinstance(lookup, dict): wheres &= q_lookup_builder(**lookup) where, params = wheres.get_query_objects(var="n") if where: script = u"%s where %s return " % (script, where) else: script = u"%s return " % script if include_properties: script = u"%s id(n), n" % script else: script = u"%s id(n)" % script page = 1000 skip = offset or 0 limit = limit or page try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None while result and "data" in result: if include_properties: for element in result["data"]: properties = element[1]["data"] elto_id = properties.pop("_id") elto_label = properties.pop("_label") properties.pop("_graph", None) yield (elto_id, properties, elto_label) else: for element in result["data"]: if len(element) > 1: yield (element[0], None, element[1]) else: yield (element[0], None, None) skip += limit if len(result["data"]) == limit: try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None else: break
def get_filtered_nodes(self, lookups, label=None, include_properties=None, limit=None, offset=None, order_by=None): # Using Cypher cypher = self.cypher if isinstance(label, (list, tuple)) and not label: return script = self._prepare_script(for_node=True, label=label) where = None params = [] if lookups: wheres = q_lookup_builder() for lookup in lookups: if isinstance(lookup, q_lookup_builder): wheres &= lookup elif isinstance(lookup, dict): wheres &= q_lookup_builder(**lookup) where, params = wheres.get_query_objects(var="n") if where: script = u"%s where %s return " % (script, where) else: script = u"%s return " % script if include_properties: script = u"%s id(n), n" % script else: script = u"%s id(n)" % script if order_by: script = u"%s order by n.`%s` %s " % (script, order_by[0][0].replace('`', '\`'), order_by[0][1]) page = 1000 skip = offset or 0 limit = limit or page try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None while result and "data" in result: if include_properties: for element in result["data"]: properties = element[1]["data"] elto_id = properties.pop("_id") elto_label = properties.pop("_label") properties.pop("_graph", None) yield (elto_id, properties, elto_label) else: for element in result["data"]: if len(element) > 1: yield (element[0], None, element[1]) else: yield (element[0], None, None) skip += limit if len(result["data"]) == limit: try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None else: break
def _query_generator_conditions(self, conditions_dict): # This list is used to control when use the index for the relationship, # in the origins or in the patterns conditions_alias = set() elems = q_lookup_builder() for condition_dict in conditions_dict: lookup, property_tuple, match, connector, datatype = condition_dict conditions_alias.add(property_tuple[1]) # This is the option to have properties of another boxes # We need to check 'property_box' too for the old queries if datatype in ['f_expression', 'property_box']: # We catch exception of type IndexError, in case that we # doesn't receive an appropiate array. try: match = self._query_generator_f_expression(match, datatype) except IndexError: match = { "var": "", "property": "", } if lookup == "between": gte = q_lookup_builder(property=property_tuple[2], lookup="gte", match=match[0], nullable=True, var=property_tuple[1], datatype=datatype[0]) lte = q_lookup_builder(property=property_tuple[2], lookup="lte", match=match[1], nullable=True, var=property_tuple[1], datatype=datatype[1]) q_element = (gte & lte) elif lookup == 'idoesnotcontain': q_element = ~q_lookup_builder(property=property_tuple[2], lookup="icontains", match=match, nullable=True, var=property_tuple[1], datatype=datatype) else: q_element = q_lookup_builder(property=property_tuple[2], lookup=lookup, match=match, nullable=True, var=property_tuple[1], datatype=datatype) if connector.upper() == "OR": elems |= q_element else: elems &= q_element conditions, query_params = elems.get_query_objects() return (conditions.strip(), query_params, conditions_alias)
def _query_generator_conditions(self, conditions_dict): query_params = dict() # This list is used to control when use the index for the relationship, # in the origins or in the patterns conditions_alias = set() # conditions_set = set() # We are going to use a list because when the set add elements, # it include them in order and breaks our pattern with AND, OR conditions_set = list() conditions_indexes = enumerate(conditions_dict) conditions_length = len(conditions_dict) - 1 for lookup, property_tuple, match, connector, datatype \ in conditions_dict: # This is the option to have properties of another boxes if datatype == "property_box": match_dict = dict() # We catch exception of type IndexError, in case that we # doesn't receive an appropiate array. try: # The match can be defined in three different ways: # slug.property_id # aggregate (slug.property_id) # aggregate (DISTINCT slug.property_id) # And also, we could have two match values for # 'in between' lookups... match_results = list() match_elements = list() datatypes = list() if type(match) is not list: match_elements.append(match) datatypes.append(datatype) else: match_elements = match datatypes = datatype index = 0 while index < len(match_elements): match_element = match_elements[index] if datatypes[index] == 'property_box': # Let's check what definition we have... match_splitted = re.split('\)|\(|\\.| ', match_element) match_first_element = match_splitted[0] # We check if aggregate belongs to the aggregate # set if match_first_element not in AGGREGATES: slug = match_first_element prop = match_splitted[1] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Finally, we assign the correct values to the # dict match_dict['var'] = match_var match_dict['property'] = match_property match = match_dict else: # We have aggregate aggregate = match_first_element match_second_element = match_splitted[1] # We check if we already have the distinct # clause if match_second_element != 'DISTINCT': # We get the slug and the property slug = match_second_element prop = match_splitted[2] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Once we have the slug and the prop, we # build the # aggregate again agg_field = u"{0}({1}.{2})".format( aggregate, match_var, match_property) match_dict['aggregate'] = agg_field match = match_dict else: # We have distinct, slug and the property distinct = match_second_element # We get the slug and the property slug = match_splitted[2] prop = match_splitted[3] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Once we have the slug and the prop, we # build the aggregate again agg_field = (u"{0}({1} {2}.{3})".format( aggregate, distinct, match_var, match_property)) match_dict['aggregate'] = agg_field match = match_dict else: match = match_element index = index + 1 match_results.append(match) if len(match_results) == 1: match = match_results[0] else: match = match_results except IndexError: match_dict['var'] = "" match_dict['property'] = "" match = match_dict if lookup == "between": gte = q_lookup_builder(property=property_tuple[2], lookup="gte", match=match[0], var=property_tuple[1], datatype=datatype[0]) lte = q_lookup_builder(property=property_tuple[2], lookup="lte", match=match[1], var=property_tuple[1], datatype=datatype[1]) gte_query_objects = gte.get_query_objects(params=query_params) lte_query_objects = lte.get_query_objects(params=query_params) gte_condition = gte_query_objects[0] gte_params = gte_query_objects[1] lte_condition = lte_query_objects[0] lte_params = lte_query_objects[1] # conditions_set.add(unicode(gte_condition)) if gte_condition not in conditions_set: conditions_set.append(unicode(gte_condition)) query_params.update(gte_params) # conditions_set.add(unicode(lte_condition)) if lte_condition not in conditions_set: conditions_set.append(unicode(lte_condition)) query_params.update(lte_params) # We append the two property in the list conditions_alias.add(property_tuple[1]) elif lookup == 'idoesnotcontain': q_element = ~q_lookup_builder(property=property_tuple[2], lookup="icontains", match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] # conditions_set.add(unicode(condition)) if condition not in conditions_set: conditions_set.append(unicode(condition)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) else: q_element = q_lookup_builder(property=property_tuple[2], lookup=lookup, match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] # conditions_set.add(unicode(condition)) if condition not in conditions_set: conditions_set.append(unicode(condition)) # Uncomment this line to see the difference between use # query params or use the q_element # conditions_set.add(unicode(q_element)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) if connector != 'not': # We have to get the next element to keep the concordance elem = conditions_indexes.next() connector = u' {} '.format(connector.upper()) # conditions_set.add(connector) conditions_set.append(connector) elif connector == 'not': elem = conditions_indexes.next() if elem[0] < conditions_length: connector = u' AND ' # conditions_set.add(connector) conditions_set.append(connector) # We check if we have only one condition and one operator if len(conditions_set) > 0: conditions_last_index = len(conditions_set) - 1 conditions_last_element = conditions_set[conditions_last_index] if (conditions_last_element == ' AND ' or conditions_last_element == ' OR '): conditions_set.pop() conditions = u" ".join(conditions_set) return (conditions, query_params, conditions_alias)
def get_filtered_relationships(self, lookups, label=None, include_properties=None, limit=None, offset=None, order_by=None): # Using Cypher cypher = self.cypher if isinstance(label, (list, tuple)) and not label: return script = self._prepare_script(for_node=False, label=label) script = """%s match a-[r]->b """ % script where = None params = [] if lookups: wheres = q_lookup_builder() for lookup in lookups: if isinstance(lookup, q_lookup_builder): wheres &= lookup elif isinstance(lookup, dict): wheres &= q_lookup_builder(**lookup) where, params = wheres.get_query_objects(var="r") if include_properties: type_or_r = "r" else: type_or_r = "type(r)" if where: script = u"%s where %s return distinct id(r), %s, a, b" \ % (script, where, type_or_r) else: script = u"%s return distinct id(r), %s, a, b" \ % (script, type_or_r) if order_by: script = u"%s order by n.`%s` %s " % ( script, order_by[0][0].replace('`', '\`'), order_by[0][1]) page = 1000 skip = offset or 0 limit = limit or page try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None while result and "data" in result and len(result["data"]) > 0: if include_properties: for element in result["data"]: properties = element[1]["data"] properties.pop("_id") properties.pop("_graph", None) elto_label = properties.pop("_label") source_props = element[2]["data"] source_id = source_props.pop("_id") source_label = source_props.pop("_label") source_props.pop("_graph", None) source = { "id": source_id, "properties": source_props, "label": source_label } target_props = element[3]["data"] target_id = target_props.pop("_id") target_label = target_props.pop("_label") target_props.pop("_graph", None) target = { "id": target_id, "properties": target_props, "label": target_label } yield (element[0], properties, elto_label, source, target) else: for element in result["data"]: yield (element[0], None, element[1]) skip += page if len(result["data"]) == limit: try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None else: break
def get_filtered_relationships(self, lookups, label=None, include_properties=None, limit=None, offset=None, order_by=None): # Using Cypher cypher = self.cypher if isinstance(label, (list, tuple)) and not label: return script = self._prepare_script(for_node=False, label=label) script = """%s match a-[r]->b """ % script where = None params = [] if lookups: wheres = q_lookup_builder() for lookup in lookups: if isinstance(lookup, q_lookup_builder): wheres &= lookup elif isinstance(lookup, dict): wheres &= q_lookup_builder(**lookup) where, params = wheres.get_query_objects(var="r") if include_properties: type_or_r = "r" else: type_or_r = "type(r)" if where: script = u"%s where %s return distinct id(r), %s, a, b" \ % (script, where, type_or_r) else: script = u"%s return distinct id(r), %s, a, b" \ % (script, type_or_r) if order_by: script = u"%s order by n.`%s` %s " % (script, order_by[0][0].replace('`', '\`'), order_by[0][1]) page = 1000 skip = offset or 0 limit = limit or page try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None while result and "data" in result and len(result["data"]) > 0: if include_properties: for element in result["data"]: properties = element[1]["data"] properties.pop("_id") properties.pop("_graph", None) elto_label = properties.pop("_label") source_props = element[2]["data"] source_id = source_props.pop("_id") source_label = source_props.pop("_label") source_props.pop("_graph", None) source = { "id": source_id, "properties": source_props, "label": source_label } target_props = element[3]["data"] target_id = target_props.pop("_id") target_label = target_props.pop("_label") target_props.pop("_graph", None) target = { "id": target_id, "properties": target_props, "label": target_label } yield (element[0], properties, elto_label, source, target) else: for element in result["data"]: yield (element[0], None, element[1]) skip += page if len(result["data"]) == limit: try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(query=paged_script, params=params) except: result = None else: break
def _query_generator_conditions(self, conditions_dict): query_params = dict() # This list is used to control when use the index for the relationship, # in the origins or in the patterns conditions_alias = set() conditions_set = set() conditions_indexes = enumerate(conditions_dict) conditions_length = len(conditions_dict) - 1 for lookup, property_tuple, match, connector, datatype \ in conditions_dict: if lookup == "between": gte = q_lookup_builder(property=property_tuple[2], lookup="gte", match=match[0], var=property_tuple[1], datatype=datatype) lte = q_lookup_builder(property=property_tuple[2], lookup="lte", match=match[1], var=property_tuple[1], datatype=datatype) gte_query_objects = gte.get_query_objects(params=query_params) lte_query_objects = lte.get_query_objects(params=query_params) gte_condition = gte_query_objects[0] gte_params = gte_query_objects[1] lte_condition = lte_query_objects[0] lte_params = lte_query_objects[1] conditions_set.add(unicode(gte_condition)) query_params.update(gte_params) conditions_set.add(unicode(lte_condition)) query_params.update(lte_params) # We append the two property in the list conditions_alias.add(property_tuple[1]) elif lookup == 'idoesnotcontain': q_element = ~q_lookup_builder(property=property_tuple[2], lookup="icontains", match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] conditions_set.add(unicode(condition)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) else: q_element = q_lookup_builder(property=property_tuple[2], lookup=lookup, match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] conditions_set.add(unicode(condition)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) if connector != 'not': # We have to get the next element to keep the concordance elem = conditions_indexes.next() connector = u' {} '.format(connector.upper()) conditions_set.add(connector) elif connector == 'not': elem = conditions_indexes.next() if elem[0] < conditions_length: connector = u' AND ' conditions_set.add(connector) conditions = u" ".join(conditions_set) return (conditions, query_params, conditions_alias)
def _query_generator_conditions(self, conditions_dict): query_params = dict() # This list is used to control when use the index for the relationship, # in the origins or in the patterns conditions_alias = set() # conditions_set = set() # We are going to use a list because when the set add elements, # it include them in order and breaks our pattern with AND, OR conditions_set = list() conditions_indexes = enumerate(conditions_dict) conditions_length = len(conditions_dict) - 1 for lookup, property_tuple, match, connector, datatype \ in conditions_dict: # This is the option to have properties of another boxes if datatype == "property_box": match_dict = dict() # We catch exception of type IndexError, in case that we # doesn't receive an appropiate array. try: # The match can be defined in three different ways: # slug.property_id # aggregate (slug.property_id) # aggregate (DISTINCT slug.property_id) # And also, we could have two match values for # 'in between' lookups... match_results = list() match_elements = list() datatypes = list() if type(match) is not list: match_elements.append(match) datatypes.append(datatype) else: match_elements = match datatypes = datatype index = 0 while index < len(match_elements): match_element = match_elements[index] if datatypes[index] == 'property_box': # Let's check what definition we have... match_splitted = re.split('\)|\(|\\.| ', match_element) match_first_element = match_splitted[0] # We check if aggregate belongs to the aggregate # set if match_first_element not in AGGREGATES: slug = match_first_element prop = match_splitted[1] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Finally, we assign the correct values to the # dict match_dict['var'] = match_var match_dict['property'] = match_property match = match_dict else: # We have aggregate aggregate = match_first_element match_second_element = match_splitted[1] # We check if we already have the distinct # clause if match_second_element != 'DISTINCT': # We get the slug and the property slug = match_second_element prop = match_splitted[2] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Once we have the slug and the prop, we # build the # aggregate again agg_field = u"{0}({1}.{2})".format( aggregate, match_var, match_property) match_dict['aggregate'] = agg_field match = match_dict else: # We have distinct, slug and the property distinct = match_second_element # We get the slug and the property slug = match_splitted[2] prop = match_splitted[3] match_var, match_property = ( self._get_slug_and_prop(slug, prop)) # Once we have the slug and the prop, we # build the aggregate again agg_field = ( u"{0}({1} {2}.{3})".format( aggregate, distinct, match_var, match_property)) match_dict['aggregate'] = agg_field match = match_dict else: match = match_element index = index + 1 match_results.append(match) if len(match_results) == 1: match = match_results[0] else: match = match_results except IndexError: match_dict['var'] = "" match_dict['property'] = "" match = match_dict if lookup == "between": gte = q_lookup_builder(property=property_tuple[2], lookup="gte", match=match[0], var=property_tuple[1], datatype=datatype[0]) lte = q_lookup_builder(property=property_tuple[2], lookup="lte", match=match[1], var=property_tuple[1], datatype=datatype[1]) gte_query_objects = gte.get_query_objects(params=query_params) lte_query_objects = lte.get_query_objects(params=query_params) gte_condition = gte_query_objects[0] gte_params = gte_query_objects[1] lte_condition = lte_query_objects[0] lte_params = lte_query_objects[1] # conditions_set.add(unicode(gte_condition)) if gte_condition not in conditions_set: conditions_set.append(unicode(gte_condition)) query_params.update(gte_params) # conditions_set.add(unicode(lte_condition)) if lte_condition not in conditions_set: conditions_set.append(unicode(lte_condition)) query_params.update(lte_params) # We append the two property in the list conditions_alias.add(property_tuple[1]) elif lookup == 'idoesnotcontain': q_element = ~q_lookup_builder(property=property_tuple[2], lookup="icontains", match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] # conditions_set.add(unicode(condition)) if condition not in conditions_set: conditions_set.append(unicode(condition)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) else: q_element = q_lookup_builder(property=property_tuple[2], lookup=lookup, match=match, var=property_tuple[1], datatype=datatype) query_objects = q_element.get_query_objects( params=query_params) condition = query_objects[0] params = query_objects[1] # conditions_set.add(unicode(condition)) if condition not in conditions_set: conditions_set.append(unicode(condition)) # Uncomment this line to see the difference between use # query params or use the q_element # conditions_set.add(unicode(q_element)) query_params.update(params) # We append the two property in the list conditions_alias.add(property_tuple[1]) if connector != 'not': # We have to get the next element to keep the concordance elem = conditions_indexes.next() connector = u' {} '.format(connector.upper()) # conditions_set.add(connector) conditions_set.append(connector) elif connector == 'not': elem = conditions_indexes.next() if elem[0] < conditions_length: connector = u' AND ' # conditions_set.add(connector) conditions_set.append(connector) # We check if we have only one condition and one operator if len(conditions_set) > 0: conditions_last_index = len(conditions_set) - 1 conditions_last_element = conditions_set[conditions_last_index] if (conditions_last_element == ' AND ' or conditions_last_element == ' OR '): conditions_set.pop() conditions = u" ".join(conditions_set) return (conditions, query_params, conditions_alias)
def get_filtered_relationships(self, lookups, label=None, include_properties=None, source_id=None, target_id=None, directed=True, limit=None, offset=None, order_by=None): # Using Cypher cypher = self.cypher if isinstance(label, (list, tuple)) and not label: return script = self._prepare_script(for_node=False, label=label) if source_id and target_id: script = """%s, a=node(%s), b=node(%s)""" % ( script, source_id, target_id) elif source_id and not target_id: script = """%s, a=node(%s)""" % (script, source_id) elif not source_id and target_id: script = """%s, b=node(%s)""" % (script, target_id) if directed: script = """%s match (a)-[r]->(b) """ % script else: script = """%s match (a)-[r]-(b) """ % script where = None params = {} if lookups: wheres = q_lookup_builder() for lookup in lookups: if isinstance(lookup, q_lookup_builder): wheres &= lookup elif isinstance(lookup, dict): wheres &= q_lookup_builder(**lookup) where, params = wheres.get_query_objects(var="r") if include_properties: type_or_r = "r" else: type_or_r = "type(r)" if where: script = u"%s where %s return distinct id(r), %s, a, b" \ % (script, where, type_or_r) else: script = u"%s return distinct id(r), %s, a, b" \ % (script, type_or_r) if order_by: script = u"%s order by n.`%s` %s " % ( script, order_by[0][0].replace(u'`', u'\\`'), order_by[0][1] ) page = 1000 skip = offset or 0 limit = limit or page try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(q=paged_script, params=params) except: result = None while result and "data" in result and len(result["data"]) > 0: if include_properties: for element in result["data"]: yield self._get_filtered_relationships_properties(element) else: for element in result["data"]: yield (element[0], None, element[1]) skip += page if len(result["data"]) == limit: try: paged_script = "%s skip %s limit %s" % (script, skip, limit) result = cypher(q=paged_script, params=params) except: result = None else: break