cancancan-neo4j 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|