set_property_value()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
c 2
b 0
f 0
dl 0
loc 21
rs 9.3142
1
# Copyright (c) 2016 Fabian Kochem
2
3
4
import json
5
6
from libtree.core.node_data import NodeData
7
from libtree.core.query import get_ancestors, get_node
8
from libtree.utils import recursive_dict_merge
9
10
11
def get_nodes_by_property_dict(cur, query):
12
    """
13
    Return an iterator that yields a ``NodeData`` object of every node
14
    which contains all key/value pairs of ``query`` in its property
15
    dictionary. Inherited keys are not considered.
16
17
    :param dict query: The dictionary to search for
18
    """
19
    sql = """
20
        SELECT
21
          *
22
        FROM
23
          nodes
24
        WHERE
25
          properties @> %s;
26
    """
27
    cur.execute(sql, (json.dumps(query), ))
28
    for result in cur:
29
        yield NodeData(**result)
30
31
32
def get_nodes_by_property_key(cur, key):
33
    """
34
    Return an iterator that yields a ``NodeData`` object of every node
35
    which contains ``key`` in its property dictionary. Inherited keys
36
    are not considered.
37
38
    :param str key: The key to search for
39
    """
40
    sql = """
41
        SELECT
42
          *
43
        FROM
44
          nodes
45
        WHERE
46
          properties ? %s;
47
    """
48
    cur.execute(sql, (key, ))
49
    for result in cur:
50
        yield NodeData(**result)
51
52
53
def get_nodes_by_property_value(cur, key, value):
54
    """
55
    Return an iterator that yields a ``NodeData`` object of every node
56
    which has ``key`` exactly set to ``value`` in its property
57
    dictionary. Inherited keys are not considered.
58
59
    :param str key: The key to search for
60
    :param object value: The exact value to sarch for
61
    """
62
    query = {key: value}
63
    for node in get_nodes_by_property_dict(cur, query):
64
        yield node
65
66
67
def get_inherited_properties(cur, node):
68
    """
69
    Get the entire inherited property dictionary.
70
71
    To calculate this, the trees path from root node till ``node`` will
72
    be traversed. For each level, the property dictionary will be merged
73
    into the previous one. This is a simple merge, only the first level
74
    of keys will be combined.
75
76
    :param node:
77
    :type node: Node or uuid4
78
    :rtype: dict
79
    """
80
    ret = {}
81
    id = str(node)
82
    if isinstance(node, str):
83
        node = get_node(cur, id)
84
85
    ancestors = list(get_ancestors(cur, id))
86
87
    for ancestor in ancestors[::-1]:  # Go top down
88
        ret.update(ancestor.properties)
89
90
    ret.update(node.properties)
91
92
    return ret
93
94
95
def get_inherited_property_value(cur, node, key):
96
    """
97
    Get the inherited value for a single property key.
98
99
    :param node:
100
    :type node: Node or uuid4
101
    :param key: str
102
    """
103
    return get_inherited_properties(cur, node)[key]
104
105
106
def get_recursive_properties(cur, node):
107
    """
108
    Get the entire inherited and recursively merged property dictionary.
109
110
    To calculate this, the trees path from root node till ``node`` will
111
    be traversed. For each level, the property dictionary will be merged
112
    into the previous one. This is a recursive merge, so all dictionary
113
    levels will be combined.
114
115
    :param node:
116
    :type node: Node or uuid4
117
    :rtype: dict
118
    """
119
    ret = {}
120
    id = str(node)
121
    if isinstance(node, str):
122
        node = get_node(cur, id)
123
124
    ancestors = list(get_ancestors(cur, id))
125
126
    for ancestor in ancestors[::-1]:  # Go top down
127
        recursive_dict_merge(ret, ancestor.properties, create_copy=False)
128
129
    recursive_dict_merge(ret, node.properties, create_copy=False)
130
131
    return ret
132
133
134
def set_properties(cur, node, new_properties):
135
    """
136
    Set the property dictionary to ``new_properties``.
137
    Return ``NodeData`` object with updated properties.
138
139
    :param node:
140
    :type node: Node or uuid4
141
    :param new_properties: dict
142
    """
143
    if not isinstance(new_properties, dict):
144
        raise TypeError('Only dictionaries are supported.')
145
146
    id = str(node)
147
    if isinstance(node, str):
148
        node = get_node(cur, id)
149
150
    sql = """
151
        UPDATE
152
          nodes
153
        SET
154
          properties=%s
155
        WHERE
156
          id=%s;
157
    """
158
    cur.execute(sql, (json.dumps(new_properties), str(node)))
159
160
    kwargs = node.to_dict()
161
    kwargs['properties'] = new_properties
162
    return NodeData(**kwargs)
163
164
165
def update_properties(cur, node, new_properties):
166
    """
167
    Update existing property dictionary with another dictionary.
168
    Return ``NodeData`` object with updated properties.
169
170
    :param node:
171
    :type node: Node or uuid4
172
    :param new_properties: dict
173
    """
174
    if not isinstance(new_properties, dict):
175
        raise TypeError('Only dictionaries are supported.')
176
177
    id = str(node)
178
    if isinstance(node, str):
179
        node = get_node(cur, id)
180
181
    properties = node.properties.copy()
182
    properties.update(new_properties)
183
    return set_properties(cur, node, properties)
184
185
186
def set_property_value(cur, node, key, value):
187
    """
188
    Set the value for a single property key.
189
    Return ``NodeData`` object with updated properties.
190
191
    :param node:
192
    :type node: Node or uuid4
193
    :param key: str
194
    :param value: object
195
    """
196
    id = str(node)
197
    if isinstance(node, str):
198
        node = get_node(cur, id)
199
200
    properties = node.properties.copy()
201
    properties[key] = value
202
    set_properties(cur, node, properties)
203
204
    kwargs = node.to_dict()
205
    kwargs['properties'] = properties
206
    return NodeData(**kwargs)
207