cancancan-neo4j 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/cancancan-neo4j.gemspec +1 -2
- data/lib/cancancan/model_adapters/neo4j_adapter.rb +34 -63
- data/lib/cancancan/neo4j.rb +1 -0
- data/lib/cancancan/neo4j/cypher_constructor.rb +83 -0
- data/lib/cancancan/neo4j/cypher_constructor_helper.rb +16 -58
- data/lib/cancancan/neo4j/rule_cypher.rb +67 -26
- data/lib/cancancan/neo4j/version.rb +1 -1
- metadata +27 -55
- data/lib/cancancan/neo4j/association_conditions.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80f5ce945f4e2b8449a73be0c5d203c47899f2ce2d0332bfb9db82bff568e4c1
|
4
|
+
data.tar.gz: 9ac02736ba3b4ae898f67c954c45dac7059d9e4c867795699b1bc64a7036d965
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1f6de129648660e99814b2e3a2869f35d62d105879bc2d2b4e75e58c9e1a4ed0db2a15a688df731c11717dbef9db1ae1ee984a3c3d6c5155b0655b13d533c46
|
7
|
+
data.tar.gz: 26393b95bc052363bbc607e05ad740dead1bc8fc7829dd2705bdddcd21d491ae160084489b56c6520230d77ff5a26b8932dc95b4d63a6781d4c319d5da138b96
|
data/cancancan-neo4j.gemspec
CHANGED
@@ -18,8 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.files = `git ls-files lib init.rb cancancan-neo4j.gemspec`.split($INPUT_RECORD_SEPARATOR)
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency '
|
22
|
-
spec.add_dependency 'cancancan', '<=2.1.4'
|
21
|
+
spec.add_dependency 'cancancan'
|
23
22
|
spec.add_dependency 'neo4j', '>= 9.0.0'
|
24
23
|
|
25
24
|
spec.add_development_dependency 'bundler', '>= 1.3'
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'cancancan/neo4j/cypher_constructor_helper'
|
2
2
|
require 'cancancan/neo4j/rule_cypher'
|
3
|
+
require 'cancancan/neo4j/cypher_constructor'
|
3
4
|
|
4
5
|
module CanCan
|
5
6
|
module ModelAdapters
|
@@ -26,99 +27,69 @@ module CanCan
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def self.all_conditions_match?(subject, conditions, base_class)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
return true if conditions.blank?
|
37
|
-
conditions = conditions.partition do |key, _|
|
38
|
-
base_class.associations_keys.include?(key)
|
39
|
-
end
|
40
|
-
associations_conditions, atrribute_conditions = conditions.map(&:to_h)
|
41
|
-
matches_attribute_conditions?(atrribute_conditions, subject) &&
|
42
|
-
matches_associations_relations(associations_conditions, subject)
|
43
|
-
end
|
44
|
-
|
45
|
-
# checks if associations exists on given node
|
46
|
-
def self.matches_associations_relations(conditions, subject)
|
47
|
-
return true if conditions.blank?
|
48
|
-
conditions.all? do |association, value|
|
49
|
-
association_exists = subject.send(association).exists?
|
50
|
-
value ? association_exists : !association_exists
|
30
|
+
return false unless subject
|
31
|
+
conditions.all? do |key, value|
|
32
|
+
if (relation = base_class.associations[key])
|
33
|
+
match_relation_conditions(value, subject, relation)
|
34
|
+
else
|
35
|
+
property_matches?(subject, key, value)
|
36
|
+
end
|
51
37
|
end
|
52
38
|
end
|
53
39
|
|
54
|
-
def self.
|
55
|
-
return true if conditions.blank?
|
40
|
+
def self.property_matches?(subject, property, value)
|
56
41
|
if subject.is_a?(Neo4j::ActiveNode::HasN::AssociationProxy)
|
57
|
-
subject.where(
|
42
|
+
subject.where(property => value).exists?
|
58
43
|
else
|
59
|
-
|
60
|
-
subject.send(attribute) == value
|
61
|
-
end
|
44
|
+
subject.send(property) == value
|
62
45
|
end
|
63
46
|
end
|
64
47
|
|
65
|
-
def self.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
current_model = base_class.associations[association].target_class
|
72
|
-
all_conditions_match?(current_subject, conditions_hash, current_model)
|
73
|
-
end
|
48
|
+
def self.match_relation_conditions(conditions, subject, association)
|
49
|
+
rel_length = conditions.delete(:rel_length) if conditions.is_a?(Hash)
|
50
|
+
subject = subject.send(association.name, rel_length: rel_length)
|
51
|
+
return !subject.exists? if conditions.blank?
|
52
|
+
return subject.exists? if conditions == true
|
53
|
+
all_conditions_match?(subject, conditions, association.target_class)
|
74
54
|
end
|
75
55
|
|
76
56
|
private
|
77
57
|
|
78
58
|
def records_for_multiple_rules
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
base_query = base_query.match(match_string) unless match_string.blank?
|
84
|
-
base_query
|
85
|
-
.proxy_as(@model_class, var_name(@model_class))
|
86
|
-
.where(cypher_options[:conditions])
|
59
|
+
CanCanCan::Neo4j::CypherConstructor
|
60
|
+
.new(construct_cypher_options)
|
61
|
+
.query
|
62
|
+
.proxy_as(@model_class, var_name)
|
87
63
|
end
|
88
64
|
|
89
65
|
def construct_cypher_options
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
rule_cypher = CanCanCan::Neo4j::RuleCypher.new(rule_options)
|
94
|
-
CanCanCan::Neo4j::CypherConstructorHelper
|
95
|
-
.append_and_or_to_conditions(options, rule_cypher)
|
96
|
-
options[:conditions] += ('(' + rule_cypher.rule_conditions + ')')
|
97
|
-
options[:matches] += rule_cypher.cypher_matches
|
98
|
-
options
|
66
|
+
@rules.reverse.collect.with_index do |rule, index|
|
67
|
+
opts = { rule: rule, model_class: @model_class, index: index }
|
68
|
+
CanCanCan::Neo4j::RuleCypher.new(opts)
|
99
69
|
end
|
100
70
|
end
|
101
71
|
|
102
|
-
def base_query_proxy
|
103
|
-
@model_class.as(var_name(@model_class))
|
104
|
-
end
|
105
|
-
|
106
72
|
def override_scope
|
107
73
|
conditions = @rules.map(&:conditions).compact
|
108
|
-
return unless conditions.any?
|
74
|
+
return unless conditions.any? do |condition|
|
75
|
+
condition.is_a?(Neo4j::ActiveNode::Query::QueryProxy)
|
76
|
+
end
|
109
77
|
return conditions.first if conditions.size == 1
|
110
78
|
raise_override_scope_error
|
111
79
|
end
|
112
80
|
|
113
81
|
def raise_override_scope_error
|
114
|
-
rule_found = @rules.detect
|
82
|
+
rule_found = @rules.detect do |rule|
|
83
|
+
rule.conditions.is_a?(Neo4j::ActiveNode::Query::QueryProxy)
|
84
|
+
end
|
115
85
|
raise Error,
|
116
86
|
'Unable to merge an ActiveNode scope with other conditions. '\
|
117
|
-
"Instead use a hash for #{rule_found.actions.first}
|
87
|
+
"Instead use a hash for #{rule_found.actions.first}"\
|
88
|
+
" #{rule_found.subjects.first} ability."
|
118
89
|
end
|
119
90
|
|
120
|
-
def var_name
|
121
|
-
CanCanCan::Neo4j::CypherConstructorHelper.var_name(model_class)
|
91
|
+
def var_name
|
92
|
+
CanCanCan::Neo4j::CypherConstructorHelper.var_name(@model_class)
|
122
93
|
end
|
123
94
|
end
|
124
95
|
end
|
data/lib/cancancan/neo4j.rb
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'cancancan/neo4j/cypher_constructor_helper'
|
2
|
+
|
3
|
+
module CanCanCan
|
4
|
+
module Neo4j
|
5
|
+
# Constructs cypher query from rule cypher options
|
6
|
+
class CypherConstructor
|
7
|
+
attr_reader :query
|
8
|
+
|
9
|
+
def initialize(rule_cyphers)
|
10
|
+
@model_class = rule_cyphers.first.options[:model_class]
|
11
|
+
reset_variables
|
12
|
+
construct_cypher(rule_cyphers)
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset_variables
|
16
|
+
@query = @model_class.new_query
|
17
|
+
@current_collection = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def construct_cypher(rule_cyphers)
|
21
|
+
rule_cyphers.each do |rule_cypher|
|
22
|
+
rule = rule_cypher.options[:rule]
|
23
|
+
reset_variables if rule.conditions.blank?
|
24
|
+
if rule.base_behavior
|
25
|
+
construct_can_cypher(rule_cypher)
|
26
|
+
else
|
27
|
+
construct_cannot_cypher(rule_cypher)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
unwind_query_with_distinct
|
31
|
+
end
|
32
|
+
|
33
|
+
def unwind_query_with_distinct
|
34
|
+
var = CanCanCan::Neo4j::CypherConstructorHelper.var_name(@model_class)
|
35
|
+
@query = unwind_qeury("#{var}_can")
|
36
|
+
.with("DISTINCT #{var}_can as #{var}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def unwind_qeury(var_name)
|
40
|
+
@query = @query.unwind("#{@current_collection} as #{var_name}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def construct_can_cypher(rule_cypher)
|
44
|
+
with_clause = with_clause_for_rule(rule_cypher, true)
|
45
|
+
@query = @query.optional_match(rule_cypher.path)
|
46
|
+
.where(rule_cypher.rule_conditions)
|
47
|
+
.with(with_clause)
|
48
|
+
end
|
49
|
+
|
50
|
+
def with_clause_for_rule(rule_cypher, can_rule)
|
51
|
+
var = rule_cypher.options[:var_label]
|
52
|
+
with = "collect(DISTINCT #{var}) as #{var}_col"
|
53
|
+
if can_rule && @current_collection
|
54
|
+
with = "#{@current_collection} + #{with}"
|
55
|
+
end
|
56
|
+
@current_collection = "#{var}_col"
|
57
|
+
with
|
58
|
+
end
|
59
|
+
|
60
|
+
def construct_cannot_cypher(rule_cypher)
|
61
|
+
match_cls = match_clause(rule_cypher)
|
62
|
+
unwind_for_cannot(rule_cypher)
|
63
|
+
@query = @query.break
|
64
|
+
.match(match_cls)
|
65
|
+
.where_not(rule_cypher.rule_conditions)
|
66
|
+
with_claus = with_clause_for_rule(rule_cypher, false)
|
67
|
+
@query = @query.with(with_claus)
|
68
|
+
end
|
69
|
+
|
70
|
+
def unwind_for_cannot(rule_cypher)
|
71
|
+
return unless @current_collection.present?
|
72
|
+
var = rule_cypher.options[:var_label]
|
73
|
+
@query = unwind_qeury(var)
|
74
|
+
.with("DISTINCT #{var} as #{var}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def match_clause(rule_cypher)
|
78
|
+
var = rule_cypher.options[:var_label]
|
79
|
+
@current_collection.present? ? "(#{var})" : rule_cypher.path
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -3,72 +3,30 @@ module CanCanCan
|
|
3
3
|
# Cypher query constructs
|
4
4
|
class CypherConstructorHelper
|
5
5
|
class << self
|
6
|
-
def match_node_cypher(node_class)
|
7
|
-
"(#{var_name(node_class)}:`#{node_class.mapped_label_name}`)"
|
8
|
-
end
|
9
|
-
|
10
|
-
def construct_conditions_string(conditions_hash, base_class, path = '')
|
11
|
-
variable_name = var_name(base_class)
|
12
|
-
conditions_hash.collect do |key, value|
|
13
|
-
condition = if base_class.associations_keys.include?(key)
|
14
|
-
con = condtion_for_path(path: path,
|
15
|
-
variable_name: variable_name,
|
16
|
-
base_class: base_class,
|
17
|
-
key: key)
|
18
|
-
value ? con : ' NOT ' + con
|
19
|
-
elsif key == :id
|
20
|
-
condition_for_id(base_class, variable_name, value)
|
21
|
-
else
|
22
|
-
condition_for_attribute(value, variable_name, key)
|
23
|
-
end
|
24
|
-
'(' + condition + ')'
|
25
|
-
end.join(' AND ')
|
26
|
-
end
|
27
|
-
|
28
|
-
def condition_for_attribute(value, variable_name, attribute)
|
29
|
-
lhs = variable_name + '.' + attribute.to_s
|
30
|
-
return lhs + ' IS NULL ' if value.nil?
|
31
|
-
rhs = value.to_s
|
32
|
-
rhs = "'" + rhs + "'" unless [true, false].include?(value)
|
33
|
-
lhs + '=' + rhs
|
34
|
-
end
|
35
|
-
|
36
|
-
def condtion_for_path(path:, variable_name:, base_class:, key:)
|
37
|
-
path = "(#{variable_name})" if path.blank?
|
38
|
-
relationship = base_class.associations[key]
|
39
|
-
path + relationship.arrow_cypher + path_end_node(relationship)
|
40
|
-
end
|
41
|
-
|
42
|
-
def condition_for_id(base_class, variable_name, value)
|
43
|
-
id_property = base_class.id_property_name
|
44
|
-
if id_property == :neo_id
|
45
|
-
"ID(#{variable_name})=#{value}"
|
46
|
-
else
|
47
|
-
variable_name + '.' + id_property.to_s + '=' + "'#{value}'"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
6
|
def var_name(class_constant)
|
52
7
|
class_constant.name.downcase.split('::').join('_')
|
53
8
|
end
|
54
9
|
|
55
|
-
def
|
56
|
-
|
10
|
+
def path_node(target_class, var_label)
|
11
|
+
label = target_class.mapped_label_names
|
12
|
+
.map { |label_name| ":`#{label_name}`" }
|
13
|
+
.join
|
14
|
+
"(#{var_label}#{label})"
|
57
15
|
end
|
58
16
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
connector += 'NOT' if rule_cypher.append_not_to_conditions?
|
67
|
-
cypher_options[:conditions] = conditions_string + connector
|
17
|
+
def variable_in_path?(relationship, conditions)
|
18
|
+
boolean = [TrueClass, FalseClass].include?(conditions.class)
|
19
|
+
return false if conditions.blank? || boolean
|
20
|
+
!relationship.target_class
|
21
|
+
.associations[conditions.keys.first]
|
22
|
+
.present?
|
68
23
|
end
|
69
24
|
|
70
|
-
def path_end_node(relationship)
|
71
|
-
|
25
|
+
def path_end_node(relationship, conditions)
|
26
|
+
with_var = variable_in_path?(relationship, conditions)
|
27
|
+
target_class = relationship.target_class
|
28
|
+
var_label = with_var ? var_name(target_class) : ''
|
29
|
+
path_node(target_class, var_label)
|
72
30
|
end
|
73
31
|
end
|
74
32
|
end
|
@@ -1,35 +1,34 @@
|
|
1
1
|
require 'cancancan/neo4j/cypher_constructor_helper'
|
2
|
-
require 'cancancan/neo4j/association_conditions'
|
3
2
|
|
4
3
|
module CanCanCan
|
5
4
|
module Neo4j
|
6
5
|
# Constructs cypher conditions for rule and cypher match classes
|
7
6
|
class RuleCypher
|
8
|
-
attr_reader :rule_conditions, :
|
7
|
+
attr_reader :rule_conditions, :path, :options
|
9
8
|
|
10
9
|
def initialize(options)
|
11
10
|
@options = options
|
12
|
-
@rule_conditions =
|
13
|
-
|
11
|
+
@rule_conditions = {}
|
12
|
+
initialize_path
|
14
13
|
construct_cypher_conditions
|
15
14
|
end
|
16
15
|
|
16
|
+
def initialize_path
|
17
|
+
model_class = @options[:model_class]
|
18
|
+
var_label = CypherConstructorHelper.var_name(model_class)
|
19
|
+
var_label += ('_' + (@options[:index] + 1).to_s)
|
20
|
+
@options[:var_label] = var_label
|
21
|
+
@path = CypherConstructorHelper.path_node(model_class, var_label)
|
22
|
+
end
|
23
|
+
|
17
24
|
def construct_cypher_conditions
|
18
25
|
if @options[:rule].conditions.blank?
|
19
26
|
condition_for_rule_without_conditions
|
20
27
|
else
|
21
|
-
|
28
|
+
construct_cypher_options
|
22
29
|
end
|
23
30
|
end
|
24
31
|
|
25
|
-
def conditions_connector
|
26
|
-
@options[:rule].base_behavior ? ' OR ' : ' AND '
|
27
|
-
end
|
28
|
-
|
29
|
-
def append_not_to_conditions?
|
30
|
-
!rule_conditions_blank? && !@options[:rule].base_behavior
|
31
|
-
end
|
32
|
-
|
33
32
|
private
|
34
33
|
|
35
34
|
def rule_conditions_blank?
|
@@ -40,23 +39,65 @@ module CanCanCan
|
|
40
39
|
@rule_conditions = @options[:rule].base_behavior ? '(true)' : '(false)'
|
41
40
|
end
|
42
41
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
append_association_conditions(associations_conditions)
|
42
|
+
def construct_cypher_options
|
43
|
+
@options[:rule].conditions.deep_dup.each do |key, conditions|
|
44
|
+
hash_cypher_options(key, conditions, @options[:model_class])
|
45
|
+
end
|
48
46
|
end
|
49
47
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
def hash_cypher_options(key, conditions, base_class)
|
49
|
+
if (rel = base_class.associations[key])
|
50
|
+
update_path_with_rel(conditions, rel)
|
51
|
+
cypher_for_relation_conditions(conditions, rel)
|
52
|
+
else
|
53
|
+
merge_conditions(key, conditions, base_class)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_path_with_rel(conditions, rel)
|
58
|
+
rel_length = conditions.delete(:rel_length) if conditions
|
59
|
+
arrow_cypher = rel.arrow_cypher(nil, {}, false, false, rel_length)
|
60
|
+
node_label = CypherConstructorHelper.path_end_node(rel, conditions)
|
61
|
+
@path += (arrow_cypher + node_label)
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
59
|
-
|
64
|
+
def cypher_for_relation_conditions(conditions, relationship)
|
65
|
+
if conditions.is_a?(Hash)
|
66
|
+
conditions.each do |key, con|
|
67
|
+
hash_cypher_options(key, con, relationship.target_class)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
update_conditions_with_path(conditions ? '' : 'NOT ')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_conditions_with_path(not_str)
|
75
|
+
@rule_conditions = not_str + @path
|
76
|
+
initialize_path
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge_conditions(key, value, base_class)
|
80
|
+
var_name = var_label_for_conditions(base_class, key)
|
81
|
+
if key == :id
|
82
|
+
merge_condition_for_id(var_name, base_class, value)
|
83
|
+
else
|
84
|
+
(@rule_conditions[var_name] ||= {}).merge!(key => value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def var_label_for_conditions(base_class, key)
|
89
|
+
condition_keys = @options[:rule].conditions.keys
|
90
|
+
return @options[:var_label] if condition_keys.include?(key)
|
91
|
+
CypherConstructorHelper.var_name(base_class)
|
92
|
+
end
|
93
|
+
|
94
|
+
def merge_condition_for_id(var_name, base_class, value)
|
95
|
+
id_property_name = base_class.id_property_name
|
96
|
+
if id_property_name == :neo_id
|
97
|
+
@rule_conditions.merge!("ID(#{var_name})" => value)
|
98
|
+
else
|
99
|
+
(@rule_conditions[var_name] ||= {}).merge!(id_property_name => value)
|
100
|
+
end
|
60
101
|
end
|
61
102
|
end
|
62
103
|
end
|
metadata
CHANGED
@@ -1,150 +1,122 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cancancan-neo4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amit Suryavanshi
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: cancancan
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- - "
|
17
|
+
- - ">="
|
17
18
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
19
|
-
name: activemodel
|
20
|
-
prerelease: false
|
19
|
+
version: '0'
|
21
20
|
type: :runtime
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "<"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 5.2.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
requirement: !ruby/object:Gem::Requirement
|
29
|
-
requirements:
|
30
|
-
- - "<="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 2.1.4
|
33
|
-
name: cancancan
|
34
21
|
prerelease: false
|
35
|
-
type: :runtime
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
|
-
- - "
|
24
|
+
- - ">="
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
26
|
+
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
name: neo4j
|
42
29
|
requirement: !ruby/object:Gem::Requirement
|
43
30
|
requirements:
|
44
31
|
- - ">="
|
45
32
|
- !ruby/object:Gem::Version
|
46
33
|
version: 9.0.0
|
47
|
-
name: neo4j
|
48
|
-
prerelease: false
|
49
34
|
type: :runtime
|
35
|
+
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
38
|
- - ">="
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: 9.0.0
|
55
41
|
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
56
43
|
requirement: !ruby/object:Gem::Requirement
|
57
44
|
requirements:
|
58
45
|
- - ">="
|
59
46
|
- !ruby/object:Gem::Version
|
60
47
|
version: '1.3'
|
61
|
-
name: bundler
|
62
|
-
prerelease: false
|
63
48
|
type: :development
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.3'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '0'
|
75
|
-
name: neo4j-community
|
76
49
|
prerelease: false
|
77
|
-
type: :development
|
78
50
|
version_requirements: !ruby/object:Gem::Requirement
|
79
51
|
requirements:
|
80
52
|
- - ">="
|
81
53
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
54
|
+
version: '1.3'
|
83
55
|
- !ruby/object:Gem::Dependency
|
56
|
+
name: neo4j-rake_tasks
|
84
57
|
requirement: !ruby/object:Gem::Requirement
|
85
58
|
requirements:
|
86
59
|
- - ">="
|
87
60
|
- !ruby/object:Gem::Version
|
88
61
|
version: 0.3.0
|
89
|
-
name: neo4j-rake_tasks
|
90
|
-
prerelease: false
|
91
62
|
type: :development
|
63
|
+
prerelease: false
|
92
64
|
version_requirements: !ruby/object:Gem::Requirement
|
93
65
|
requirements:
|
94
66
|
- - ">="
|
95
67
|
- !ruby/object:Gem::Version
|
96
68
|
version: 0.3.0
|
97
69
|
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
98
71
|
requirement: !ruby/object:Gem::Requirement
|
99
72
|
requirements:
|
100
73
|
- - ">="
|
101
74
|
- !ruby/object:Gem::Version
|
102
75
|
version: 0.11.3
|
103
|
-
name: pry
|
104
|
-
prerelease: false
|
105
76
|
type: :development
|
77
|
+
prerelease: false
|
106
78
|
version_requirements: !ruby/object:Gem::Requirement
|
107
79
|
requirements:
|
108
80
|
- - ">="
|
109
81
|
- !ruby/object:Gem::Version
|
110
82
|
version: 0.11.3
|
111
83
|
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
112
85
|
requirement: !ruby/object:Gem::Requirement
|
113
86
|
requirements:
|
114
87
|
- - ">="
|
115
88
|
- !ruby/object:Gem::Version
|
116
89
|
version: '10.1'
|
117
|
-
name: rake
|
118
|
-
prerelease: false
|
119
90
|
type: :development
|
91
|
+
prerelease: false
|
120
92
|
version_requirements: !ruby/object:Gem::Requirement
|
121
93
|
requirements:
|
122
94
|
- - ">="
|
123
95
|
- !ruby/object:Gem::Version
|
124
96
|
version: '10.1'
|
125
97
|
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
126
99
|
requirement: !ruby/object:Gem::Requirement
|
127
100
|
requirements:
|
128
101
|
- - ">="
|
129
102
|
- !ruby/object:Gem::Version
|
130
103
|
version: '3.2'
|
131
|
-
name: rspec
|
132
|
-
prerelease: false
|
133
104
|
type: :development
|
105
|
+
prerelease: false
|
134
106
|
version_requirements: !ruby/object:Gem::Requirement
|
135
107
|
requirements:
|
136
108
|
- - ">="
|
137
109
|
- !ruby/object:Gem::Version
|
138
110
|
version: '3.2'
|
139
111
|
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
140
113
|
requirement: !ruby/object:Gem::Requirement
|
141
114
|
requirements:
|
142
115
|
- - ">="
|
143
116
|
- !ruby/object:Gem::Version
|
144
117
|
version: 0.48.1
|
145
|
-
name: rubocop
|
146
|
-
prerelease: false
|
147
118
|
type: :development
|
119
|
+
prerelease: false
|
148
120
|
version_requirements: !ruby/object:Gem::Requirement
|
149
121
|
requirements:
|
150
122
|
- - ">="
|
@@ -161,7 +133,7 @@ files:
|
|
161
133
|
- lib/cancancan/model_adapters/neo4j_adapter.rb
|
162
134
|
- lib/cancancan/neo4j.rb
|
163
135
|
- lib/cancancan/neo4j/active_record_disabler.rb
|
164
|
-
- lib/cancancan/neo4j/
|
136
|
+
- lib/cancancan/neo4j/cypher_constructor.rb
|
165
137
|
- lib/cancancan/neo4j/cypher_constructor_helper.rb
|
166
138
|
- lib/cancancan/neo4j/rule_cypher.rb
|
167
139
|
- lib/cancancan/neo4j/version.rb
|
@@ -169,7 +141,7 @@ homepage: https://github.com/CanCanCommunity/cancancan-neo4j
|
|
169
141
|
licenses:
|
170
142
|
- MIT
|
171
143
|
metadata: {}
|
172
|
-
post_install_message:
|
144
|
+
post_install_message:
|
173
145
|
rdoc_options: []
|
174
146
|
require_paths:
|
175
147
|
- lib
|
@@ -184,9 +156,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
156
|
- !ruby/object:Gem::Version
|
185
157
|
version: '0'
|
186
158
|
requirements: []
|
187
|
-
rubyforge_project:
|
188
|
-
rubygems_version: 2.6
|
189
|
-
signing_key:
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.7.6
|
161
|
+
signing_key:
|
190
162
|
specification_version: 4
|
191
163
|
summary: neo4j database adapter for CanCanCan.
|
192
164
|
test_files: []
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'cancancan/neo4j/cypher_constructor_helper'
|
2
|
-
|
3
|
-
module CanCanCan
|
4
|
-
module Neo4j
|
5
|
-
# Constructs cypher conditions for associations conditions hash
|
6
|
-
class AssociationConditions
|
7
|
-
attr_reader :conditions_string, :cypher_matches
|
8
|
-
|
9
|
-
def initialize(options)
|
10
|
-
@options = options
|
11
|
-
@conditions_string = ''
|
12
|
-
@cypher_matches = []
|
13
|
-
construct_conditions
|
14
|
-
end
|
15
|
-
|
16
|
-
def construct_conditions
|
17
|
-
@options[:asso_conditions].each do |association, conditions|
|
18
|
-
relationship = association_relation(association)
|
19
|
-
associations_conditions, model_conditions = CypherConstructorHelper.bifurcate_conditions(conditions)
|
20
|
-
rel_length = associations_conditions.delete(:rel_length)
|
21
|
-
current_path = append_path_to_conditions(relationship, model_conditions, rel_length)
|
22
|
-
append_model_conditions(model_conditions, relationship, current_path)
|
23
|
-
append_association_conditions(associations_conditions, relationship, rel_length)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def association_relation(association)
|
28
|
-
@options[:parent_class].associations[association]
|
29
|
-
end
|
30
|
-
|
31
|
-
def append_association_conditions(conditions, relationship, rel_length)
|
32
|
-
return if conditions.blank?
|
33
|
-
asso_conditions_obj = AssociationConditions.new(asso_conditions: conditions, parent_class: relationship.target_class, path: path_with_relationship(relationship, rel_length))
|
34
|
-
append_and_to_conditions_string
|
35
|
-
@conditions_string += asso_conditions_obj.conditions_string
|
36
|
-
@cypher_matches += asso_conditions_obj.cypher_matches
|
37
|
-
end
|
38
|
-
|
39
|
-
def append_path_to_conditions(relationship, model_conditions, rel_length)
|
40
|
-
target_class = relationship.target_class
|
41
|
-
model_attr_exists = model_conditions.any? do |key, _|
|
42
|
-
!target_class.associations_keys.include?(key)
|
43
|
-
end
|
44
|
-
to_node = CypherConstructorHelper.match_node_cypher(target_class) if model_attr_exists
|
45
|
-
current_path = path_with_relationship(relationship, rel_length, to_node)
|
46
|
-
if model_attr_exists
|
47
|
-
append_matches(relationship)
|
48
|
-
append_and_to_conditions_string
|
49
|
-
@conditions_string += current_path
|
50
|
-
end
|
51
|
-
current_path
|
52
|
-
end
|
53
|
-
|
54
|
-
def append_matches(relationship)
|
55
|
-
node_class = relationship.target_class
|
56
|
-
@cypher_matches << CypherConstructorHelper.match_node_cypher(node_class)
|
57
|
-
end
|
58
|
-
|
59
|
-
def append_and_to_conditions_string
|
60
|
-
@conditions_string += ' AND ' unless @conditions_string.blank?
|
61
|
-
end
|
62
|
-
|
63
|
-
def append_model_conditions(model_conditions, relationship, current_path)
|
64
|
-
return if model_conditions.blank?
|
65
|
-
con_string = CypherConstructorHelper.construct_conditions_string(model_conditions, relationship.target_class, current_path)
|
66
|
-
append_and_to_conditions_string
|
67
|
-
@conditions_string += con_string
|
68
|
-
end
|
69
|
-
|
70
|
-
def path_with_relationship(relationship, rel_length, to_node = nil)
|
71
|
-
arrow_cypher = relationship.arrow_cypher(nil, {}, false, false, rel_length)
|
72
|
-
to_node_label = CypherConstructorHelper.path_end_node(relationship)
|
73
|
-
@options[:path] + arrow_cypher + (to_node || to_node_label)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|