图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

263 lines
7.1 KiB

import warnings
from ..helpers import quote_string, random_string, stringify_param_value
from .commands import AsyncGraphCommands, GraphCommands
from .edge import Edge # noqa
from .node import Node # noqa
from .path import Path # noqa
DB_LABELS = "DB.LABELS"
DB_RAELATIONSHIPTYPES = "DB.RELATIONSHIPTYPES"
DB_PROPERTYKEYS = "DB.PROPERTYKEYS"
class Graph(GraphCommands):
"""
Graph, collection of nodes and edges.
"""
def __init__(self, client, name=random_string()):
"""
Create a new graph.
"""
warnings.warn(
DeprecationWarning(
"RedisGraph support is deprecated as of Redis Stack 7.2 \
(https://redis.com/blog/redisgraph-eol/)"
)
)
self.NAME = name # Graph key
self.client = client
self.execute_command = client.execute_command
self.nodes = {}
self.edges = []
self._labels = [] # List of node labels.
self._properties = [] # List of properties.
self._relationship_types = [] # List of relation types.
self.version = 0 # Graph version
@property
def name(self):
return self.NAME
def _clear_schema(self):
self._labels = []
self._properties = []
self._relationship_types = []
def _refresh_schema(self):
self._clear_schema()
self._refresh_labels()
self._refresh_relations()
self._refresh_attributes()
def _refresh_labels(self):
lbls = self.labels()
# Unpack data.
self._labels = [l[0] for _, l in enumerate(lbls)]
def _refresh_relations(self):
rels = self.relationship_types()
# Unpack data.
self._relationship_types = [r[0] for _, r in enumerate(rels)]
def _refresh_attributes(self):
props = self.property_keys()
# Unpack data.
self._properties = [p[0] for _, p in enumerate(props)]
def get_label(self, idx):
"""
Returns a label by it's index
Args:
idx:
The index of the label
"""
try:
label = self._labels[idx]
except IndexError:
# Refresh labels.
self._refresh_labels()
label = self._labels[idx]
return label
def get_relation(self, idx):
"""
Returns a relationship type by it's index
Args:
idx:
The index of the relation
"""
try:
relationship_type = self._relationship_types[idx]
except IndexError:
# Refresh relationship types.
self._refresh_relations()
relationship_type = self._relationship_types[idx]
return relationship_type
def get_property(self, idx):
"""
Returns a property by it's index
Args:
idx:
The index of the property
"""
try:
p = self._properties[idx]
except IndexError:
# Refresh properties.
self._refresh_attributes()
p = self._properties[idx]
return p
def add_node(self, node):
"""
Adds a node to the graph.
"""
if node.alias is None:
node.alias = random_string()
self.nodes[node.alias] = node
def add_edge(self, edge):
"""
Adds an edge to the graph.
"""
if not (self.nodes[edge.src_node.alias] and self.nodes[edge.dest_node.alias]):
raise AssertionError("Both edge's end must be in the graph")
self.edges.append(edge)
def _build_params_header(self, params):
if params is None:
return ""
if not isinstance(params, dict):
raise TypeError("'params' must be a dict")
# Header starts with "CYPHER"
params_header = "CYPHER "
for key, value in params.items():
params_header += str(key) + "=" + stringify_param_value(value) + " "
return params_header
# Procedures.
def call_procedure(self, procedure, *args, read_only=False, **kwagrs):
args = [quote_string(arg) for arg in args]
q = f"CALL {procedure}({','.join(args)})"
y = kwagrs.get("y", None)
if y is not None:
q += f"YIELD {','.join(y)}"
return self.query(q, read_only=read_only)
def labels(self):
return self.call_procedure(DB_LABELS, read_only=True).result_set
def relationship_types(self):
return self.call_procedure(DB_RAELATIONSHIPTYPES, read_only=True).result_set
def property_keys(self):
return self.call_procedure(DB_PROPERTYKEYS, read_only=True).result_set
class AsyncGraph(Graph, AsyncGraphCommands):
"""Async version for Graph"""
async def _refresh_labels(self):
lbls = await self.labels()
# Unpack data.
self._labels = [l[0] for _, l in enumerate(lbls)]
async def _refresh_attributes(self):
props = await self.property_keys()
# Unpack data.
self._properties = [p[0] for _, p in enumerate(props)]
async def _refresh_relations(self):
rels = await self.relationship_types()
# Unpack data.
self._relationship_types = [r[0] for _, r in enumerate(rels)]
async def get_label(self, idx):
"""
Returns a label by it's index
Args:
idx:
The index of the label
"""
try:
label = self._labels[idx]
except IndexError:
# Refresh labels.
await self._refresh_labels()
label = self._labels[idx]
return label
async def get_property(self, idx):
"""
Returns a property by it's index
Args:
idx:
The index of the property
"""
try:
p = self._properties[idx]
except IndexError:
# Refresh properties.
await self._refresh_attributes()
p = self._properties[idx]
return p
async def get_relation(self, idx):
"""
Returns a relationship type by it's index
Args:
idx:
The index of the relation
"""
try:
relationship_type = self._relationship_types[idx]
except IndexError:
# Refresh relationship types.
await self._refresh_relations()
relationship_type = self._relationship_types[idx]
return relationship_type
async def call_procedure(self, procedure, *args, read_only=False, **kwagrs):
args = [quote_string(arg) for arg in args]
q = f"CALL {procedure}({','.join(args)})"
y = kwagrs.get("y", None)
if y is not None:
f"YIELD {','.join(y)}"
return await self.query(q, read_only=read_only)
async def labels(self):
return ((await self.call_procedure(DB_LABELS, read_only=True))).result_set
async def property_keys(self):
return (await self.call_procedure(DB_PROPERTYKEYS, read_only=True)).result_set
async def relationship_types(self):
return (
await self.call_procedure(DB_RAELATIONSHIPTYPES, read_only=True)
).result_set