summaryrefslogtreecommitdiff
path: root/src/server/neo4j_qt.py
blob: 4b4ffa3f3da18b765046a119f3e7395e1fedfaec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#    This file is part of rhizi, a collaborative knowledge graph editor.
#    Copyright (C) 2014-2015  Rhizi
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.


from neo4j_cypher import Query_Struct_Type, DB_Query
from neo4j_util import rzdoc__ns_label, rzdoc__meta_ns_label
from neo4j_cypher_parser import p_path, p_node
from db_op import DBO_rzdoc__clone, DB_op
import re
import neo4j_schema

class Query_Transformation(object):
    """
    DB_op / DB_Query transformation
    """

    def __call__(self, value):
        """
        Apply transformation to either a DB_op or a DB_Query
        """
        if isinstance(value, DB_Query):
            return self.apply_to_db_op(value)
        if isinstance(value, DB_op):
            return self.apply_to_db_op(value)

    def apply_to_db_op(self, op):
        for dbq in op: # apply to sub queries
            self.apply_to_single_query(dbq)
        return op

    def apply_to_single_query(self, dbq): pass # subclass hook

class QT_RZDOC_NS_Filter__common(Query_Transformation):
    """
    Add RZDoc name-space filter:
       - inject NS labels into node patterns
       - [!] ignore nodes which are part of path patterns to avoid overriding bound references
    """

    def __init__(self, ns_label):
        self.ns_label = ns_label

    def deco__process_q_ret__n_label_set(self, label_set):
        ret = [lbl for lbl in label_set if lbl != self.ns_label]
        return ret

    def apply_to_db_op(self, op):
        ret = Query_Transformation.apply_to_db_op(self, op)

        # override DBO_rzdoc__clone.process_q_ret__n_label_set hook
        if op.__class__ == DBO_rzdoc__clone:
            op.process_q_ret__n_label_set = self.deco__process_q_ret__n_label_set

        return ret

    def apply_to_single_query(self, dbq):
        q_type = dbq.query_struct_type
        clause_set = []

        if Query_Struct_Type.w == q_type:
            clause_set += dbq.pt_root.clause_set_by_kw('create')
        if Query_Struct_Type.r == q_type:
            clause_set += dbq.pt_root.clause_set_by_kw('match')
        if Query_Struct_Type.rw == q_type:
            clause_set += dbq.pt_root.clause_set_by_kw('create')
            clause_set += dbq.pt_root.clause_set_by_kw('match')

        for c in clause_set:
            n_exp_set = c.sub_exp_set_by_type(p_node, recurse=True)
            for n_exp in n_exp_set:

                if n_exp.parent.__class__ == p_path:
                    continue;

                lbl_set = n_exp.label_set
                if not lbl_set:  # add label set if necessary
                    lbl_set = n_exp.spawn_label_set()
                lbl_set.add_label(self.ns_label)

            # log.debug('db_q trans: in clause: %s, out clause: %s' % (cur_clause, new_clause))

class QT_RZDOC_NS_Filter(QT_RZDOC_NS_Filter__common):

    def __init__(self, rzdoc):
        ns_label = rzdoc__ns_label(rzdoc)
        super(QT_RZDOC_NS_Filter, self).__init__(ns_label)

class QT_RZDOC_Meta_NS_Filter(QT_RZDOC_NS_Filter__common):

    def __init__(self, rzdoc):
        ns_label = rzdoc__meta_ns_label(rzdoc)
        super(QT_RZDOC_Meta_NS_Filter, self).__init__(ns_label)

class QT_Node_Filter__meta_label_set(Query_Transformation):
    # TODO: impl
    # 'where 0 = length(filter(_lbl in labels(n) where _lbl =~ \'^__.*$\'))',  # filter nodes with meta labels
    pass