219 lines
6.2 KiB
Python
219 lines
6.2 KiB
Python
# Copyright 2021 Memgraph Ltd.
|
|
#
|
|
# Use of this software is governed by the Business Source License
|
|
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
|
# License, and you may not use this file except in compliance with the Business Source License.
|
|
#
|
|
# As of the Change Date specified in that file, in accordance with
|
|
# the Business Source License, use of this software will be governed
|
|
# by the Apache License, Version 2.0, included in the file
|
|
# licenses/APL.txt.
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
def parse(el, ignore_order):
|
|
"""
|
|
Function used to parse result element. Result element can be
|
|
node, list, path, relationship, map or string. Function returns
|
|
same string for two same elements, etc. if properties of two nodes
|
|
are inverted, but labels and properties are the same, function
|
|
will return the same string for them. For two differenet
|
|
elements function will not return the same strings.
|
|
|
|
@param el:
|
|
string, element to parse.
|
|
@param ignore_order:
|
|
bool, ignore order inside of lists, etc. lists [1, 2, 3] and
|
|
[2, 3, 1] are the same if ignore_order is true, else false.
|
|
@return:
|
|
Parsed string of element.
|
|
"""
|
|
if el.startswith("(") and el.endswith(")"):
|
|
return parse_node(el, ignore_order)
|
|
if el.startswith("<") and el.endswith(">"):
|
|
return parse_path(el, ignore_order)
|
|
if el.startswith("{") and el.endswith("}"):
|
|
return parse_map(el, ignore_order)
|
|
if el.startswith("[") and el.endswith("]"):
|
|
if is_list(el):
|
|
return parse_list(el, ignore_order)
|
|
else:
|
|
return parse_rel(el, ignore_order)
|
|
return el
|
|
|
|
|
|
def is_list(el):
|
|
"""
|
|
Function returns true if string el is a list, else false.
|
|
@param el:
|
|
string, element to check.
|
|
@return:
|
|
true if el is list.
|
|
"""
|
|
if el[1] == ":":
|
|
return False
|
|
return True
|
|
|
|
|
|
def parse_path(path, ignore_order):
|
|
"""
|
|
Function used to parse path.
|
|
@param path:
|
|
string representing path
|
|
@return:
|
|
parsed path
|
|
"""
|
|
parsed_path = "<"
|
|
dif_open_closed_brackets = 0
|
|
for i in range(1, len(path) - 1):
|
|
if path[i] == "(" or path[i] == "{" or path[i] == "[":
|
|
dif_open_closed_brackets += 1
|
|
if dif_open_closed_brackets == 1:
|
|
start = i
|
|
if path[i] == ")" or path[i] == "}" or path[i] == "]":
|
|
dif_open_closed_brackets -= 1
|
|
if dif_open_closed_brackets == 0:
|
|
parsed_path += parse(path[start : (i + 1)], ignore_order)
|
|
elif dif_open_closed_brackets == 0:
|
|
parsed_path += path[i]
|
|
parsed_path += ">"
|
|
return parsed_path
|
|
|
|
|
|
def parse_node(node_str, ignore_order):
|
|
"""
|
|
Function used to parse node.
|
|
@param node:
|
|
string representing node
|
|
@return:
|
|
parsed node
|
|
"""
|
|
label = ""
|
|
labels = []
|
|
props_start = None
|
|
for i in range(1, len(node_str)):
|
|
if node_str[i] == ":" or node_str[i] == ")" or node_str[i] == "{":
|
|
if label.startswith(":"):
|
|
labels.append(label)
|
|
label = ""
|
|
label += node_str[i]
|
|
|
|
if node_str[i] == "{":
|
|
props_start = i
|
|
break
|
|
|
|
labels.sort()
|
|
parsed_node = "("
|
|
for label in labels:
|
|
parsed_node += label
|
|
if props_start is not None:
|
|
parsed_node += parse_map(node_str[props_start : len(node_str) - 1], ignore_order)
|
|
parsed_node += ")"
|
|
return parsed_node
|
|
|
|
|
|
def parse_map(props, ignore_order):
|
|
"""
|
|
Function used to parse map.
|
|
@param props:
|
|
string representing map
|
|
@return:
|
|
parsed map
|
|
"""
|
|
dif_open_closed_brackets = 0
|
|
prop = ""
|
|
list_props = []
|
|
for i in range(1, len(props) - 1):
|
|
if props[i] == "," and dif_open_closed_brackets == 0:
|
|
list_props.append(prop_to_str(prop, ignore_order))
|
|
prop = ""
|
|
else:
|
|
prop += props[i]
|
|
if props[i] == "(" or props[i] == "{" or props[i] == "[":
|
|
dif_open_closed_brackets += 1
|
|
elif props[i] == ")" or props[i] == "}" or props[i] == "]":
|
|
dif_open_closed_brackets -= 1
|
|
if prop != "":
|
|
list_props.append(prop_to_str(prop, ignore_order))
|
|
|
|
list_props.sort()
|
|
return "{" + ",".join(list_props) + "}"
|
|
|
|
|
|
def prop_to_str(prop, ignore_order):
|
|
"""
|
|
Function used to parse one pair of key, value in format 'key:value'.
|
|
Value must be parsed, key is string.
|
|
|
|
@param prop:
|
|
string, pair key:value to parse
|
|
@return:
|
|
parsed prop
|
|
"""
|
|
key = prop.split(":", 1)[0]
|
|
val = prop.split(":", 1)[1]
|
|
return key + ":" + parse(val, ignore_order)
|
|
|
|
|
|
def parse_list(l, ignore_order):
|
|
"""
|
|
Function used to parse list.
|
|
@param l:
|
|
string representing list
|
|
@return:
|
|
parsed list
|
|
"""
|
|
dif_open_closed_brackets = 0
|
|
el = ""
|
|
list_el = []
|
|
for i in range(1, len(l) - 1):
|
|
if l[i] == "," and dif_open_closed_brackets == 0:
|
|
list_el.append(parse(el, ignore_order))
|
|
el = ""
|
|
else:
|
|
el += l[i]
|
|
if l[i] == "(" or l[i] == "{" or l[i] == "[":
|
|
dif_open_closed_brackets += 1
|
|
elif l[i] == ")" or l[i] == "}" or l[i] == "]":
|
|
dif_open_closed_brackets -= 1
|
|
if el != "":
|
|
list_el.append(parse(el, ignore_order))
|
|
|
|
if ignore_order:
|
|
list_el.sort()
|
|
|
|
return "[" + ",".join(list_el) + "]"
|
|
|
|
|
|
def parse_rel(rel, ignore_order):
|
|
"""
|
|
Function used to parse relationship.
|
|
@param rel:
|
|
string representing relationship
|
|
@return:
|
|
parsed relationship
|
|
"""
|
|
label = ""
|
|
labels = []
|
|
props_start = None
|
|
for i in range(1, len(rel)):
|
|
if rel[i] == ":" or rel[i] == "]" or rel[i] == "{":
|
|
if label.startswith(":"):
|
|
labels.append(label)
|
|
label = ""
|
|
label += rel[i]
|
|
|
|
if rel[i] == "{":
|
|
props_start = i
|
|
break
|
|
|
|
labels.sort()
|
|
parsed_rel = "["
|
|
for label in labels:
|
|
parsed_rel += label
|
|
if props_start is not None:
|
|
parsed_rel += parse_map(rel[props_start : len(rel) - 1], ignore_order)
|
|
parsed_rel += "]"
|
|
return parsed_rel
|