activegraph 10.0.0.pre.alpha.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1989 -0
  3. data/CONTRIBUTORS +12 -0
  4. data/Gemfile +24 -0
  5. data/README.md +107 -0
  6. data/bin/rake +17 -0
  7. data/config/locales/en.yml +5 -0
  8. data/config/neo4j/add_classnames.yml +1 -0
  9. data/config/neo4j/config.yml +38 -0
  10. data/lib/neo4j.rb +116 -0
  11. data/lib/neo4j/active_base.rb +89 -0
  12. data/lib/neo4j/active_node.rb +108 -0
  13. data/lib/neo4j/active_node/callbacks.rb +8 -0
  14. data/lib/neo4j/active_node/dependent.rb +11 -0
  15. data/lib/neo4j/active_node/dependent/association_methods.rb +49 -0
  16. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +51 -0
  17. data/lib/neo4j/active_node/enum.rb +26 -0
  18. data/lib/neo4j/active_node/has_n.rb +612 -0
  19. data/lib/neo4j/active_node/has_n/association.rb +278 -0
  20. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
  21. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
  22. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
  23. data/lib/neo4j/active_node/id_property.rb +224 -0
  24. data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
  25. data/lib/neo4j/active_node/initialize.rb +21 -0
  26. data/lib/neo4j/active_node/labels.rb +207 -0
  27. data/lib/neo4j/active_node/labels/index.rb +37 -0
  28. data/lib/neo4j/active_node/labels/reloading.rb +21 -0
  29. data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
  30. data/lib/neo4j/active_node/node_wrapper.rb +54 -0
  31. data/lib/neo4j/active_node/orm_adapter.rb +82 -0
  32. data/lib/neo4j/active_node/persistence.rb +187 -0
  33. data/lib/neo4j/active_node/property.rb +60 -0
  34. data/lib/neo4j/active_node/query.rb +76 -0
  35. data/lib/neo4j/active_node/query/query_proxy.rb +374 -0
  36. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +177 -0
  37. data/lib/neo4j/active_node/query/query_proxy_eager_loading/association_tree.rb +75 -0
  38. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +110 -0
  39. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
  40. data/lib/neo4j/active_node/query/query_proxy_link.rb +139 -0
  41. data/lib/neo4j/active_node/query/query_proxy_methods.rb +302 -0
  42. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +86 -0
  43. data/lib/neo4j/active_node/query_methods.rb +68 -0
  44. data/lib/neo4j/active_node/reflection.rb +86 -0
  45. data/lib/neo4j/active_node/rels.rb +11 -0
  46. data/lib/neo4j/active_node/scope.rb +166 -0
  47. data/lib/neo4j/active_node/unpersisted.rb +48 -0
  48. data/lib/neo4j/active_node/validations.rb +59 -0
  49. data/lib/neo4j/active_rel.rb +67 -0
  50. data/lib/neo4j/active_rel/callbacks.rb +15 -0
  51. data/lib/neo4j/active_rel/initialize.rb +28 -0
  52. data/lib/neo4j/active_rel/persistence.rb +134 -0
  53. data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
  54. data/lib/neo4j/active_rel/property.rb +95 -0
  55. data/lib/neo4j/active_rel/query.rb +101 -0
  56. data/lib/neo4j/active_rel/rel_wrapper.rb +31 -0
  57. data/lib/neo4j/active_rel/related_node.rb +87 -0
  58. data/lib/neo4j/active_rel/types.rb +82 -0
  59. data/lib/neo4j/active_rel/validations.rb +8 -0
  60. data/lib/neo4j/ansi.rb +14 -0
  61. data/lib/neo4j/class_arguments.rb +39 -0
  62. data/lib/neo4j/config.rb +135 -0
  63. data/lib/neo4j/core.rb +14 -0
  64. data/lib/neo4j/core/connection_failed_error.rb +6 -0
  65. data/lib/neo4j/core/cypher_error.rb +37 -0
  66. data/lib/neo4j/core/driver.rb +66 -0
  67. data/lib/neo4j/core/has_uri.rb +63 -0
  68. data/lib/neo4j/core/instrumentable.rb +36 -0
  69. data/lib/neo4j/core/label.rb +158 -0
  70. data/lib/neo4j/core/logging.rb +44 -0
  71. data/lib/neo4j/core/node.rb +23 -0
  72. data/lib/neo4j/core/querable.rb +88 -0
  73. data/lib/neo4j/core/query.rb +487 -0
  74. data/lib/neo4j/core/query_builder.rb +32 -0
  75. data/lib/neo4j/core/query_clauses.rb +727 -0
  76. data/lib/neo4j/core/query_ext.rb +24 -0
  77. data/lib/neo4j/core/query_find_in_batches.rb +49 -0
  78. data/lib/neo4j/core/relationship.rb +13 -0
  79. data/lib/neo4j/core/responses.rb +50 -0
  80. data/lib/neo4j/core/result.rb +33 -0
  81. data/lib/neo4j/core/schema.rb +30 -0
  82. data/lib/neo4j/core/schema_errors.rb +12 -0
  83. data/lib/neo4j/core/wrappable.rb +30 -0
  84. data/lib/neo4j/errors.rb +57 -0
  85. data/lib/neo4j/migration.rb +148 -0
  86. data/lib/neo4j/migrations.rb +27 -0
  87. data/lib/neo4j/migrations/base.rb +77 -0
  88. data/lib/neo4j/migrations/check_pending.rb +20 -0
  89. data/lib/neo4j/migrations/helpers.rb +105 -0
  90. data/lib/neo4j/migrations/helpers/id_property.rb +75 -0
  91. data/lib/neo4j/migrations/helpers/relationships.rb +66 -0
  92. data/lib/neo4j/migrations/helpers/schema.rb +51 -0
  93. data/lib/neo4j/migrations/migration_file.rb +24 -0
  94. data/lib/neo4j/migrations/runner.rb +195 -0
  95. data/lib/neo4j/migrations/schema.rb +44 -0
  96. data/lib/neo4j/migrations/schema_migration.rb +14 -0
  97. data/lib/neo4j/model_schema.rb +139 -0
  98. data/lib/neo4j/paginated.rb +27 -0
  99. data/lib/neo4j/railtie.rb +105 -0
  100. data/lib/neo4j/schema/operation.rb +102 -0
  101. data/lib/neo4j/shared.rb +60 -0
  102. data/lib/neo4j/shared/attributes.rb +216 -0
  103. data/lib/neo4j/shared/callbacks.rb +68 -0
  104. data/lib/neo4j/shared/cypher.rb +37 -0
  105. data/lib/neo4j/shared/declared_properties.rb +204 -0
  106. data/lib/neo4j/shared/declared_property.rb +109 -0
  107. data/lib/neo4j/shared/declared_property/index.rb +37 -0
  108. data/lib/neo4j/shared/enum.rb +167 -0
  109. data/lib/neo4j/shared/filtered_hash.rb +79 -0
  110. data/lib/neo4j/shared/identity.rb +34 -0
  111. data/lib/neo4j/shared/initialize.rb +64 -0
  112. data/lib/neo4j/shared/marshal.rb +23 -0
  113. data/lib/neo4j/shared/mass_assignment.rb +64 -0
  114. data/lib/neo4j/shared/permitted_attributes.rb +28 -0
  115. data/lib/neo4j/shared/persistence.rb +282 -0
  116. data/lib/neo4j/shared/property.rb +240 -0
  117. data/lib/neo4j/shared/query_factory.rb +102 -0
  118. data/lib/neo4j/shared/rel_type_converters.rb +43 -0
  119. data/lib/neo4j/shared/serialized_properties.rb +30 -0
  120. data/lib/neo4j/shared/type_converters.rb +433 -0
  121. data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
  122. data/lib/neo4j/shared/typecaster.rb +53 -0
  123. data/lib/neo4j/shared/validations.rb +44 -0
  124. data/lib/neo4j/tasks/migration.rake +202 -0
  125. data/lib/neo4j/timestamps.rb +11 -0
  126. data/lib/neo4j/timestamps/created.rb +9 -0
  127. data/lib/neo4j/timestamps/updated.rb +9 -0
  128. data/lib/neo4j/transaction.rb +139 -0
  129. data/lib/neo4j/type_converters.rb +7 -0
  130. data/lib/neo4j/undeclared_properties.rb +53 -0
  131. data/lib/neo4j/version.rb +3 -0
  132. data/lib/neo4j/wrapper.rb +4 -0
  133. data/lib/rails/generators/neo4j/migration/migration_generator.rb +14 -0
  134. data/lib/rails/generators/neo4j/migration/templates/migration.erb +9 -0
  135. data/lib/rails/generators/neo4j/model/model_generator.rb +88 -0
  136. data/lib/rails/generators/neo4j/model/templates/migration.erb +9 -0
  137. data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
  138. data/lib/rails/generators/neo4j/upgrade_v8/templates/migration.erb +17 -0
  139. data/lib/rails/generators/neo4j/upgrade_v8/upgrade_v8_generator.rb +32 -0
  140. data/lib/rails/generators/neo4j_generator.rb +119 -0
  141. data/neo4j.gemspec +51 -0
  142. metadata +421 -0
@@ -0,0 +1,177 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ module QueryProxyEagerLoading
5
+ class IdentityMap < Hash
6
+ def add(node)
7
+ self[node.neo_id] ||= node
8
+ end
9
+ end
10
+
11
+ def pluck_vars(node, rel)
12
+ with_associations_tree.empty? ? super : perform_query
13
+ end
14
+
15
+ def perform_query
16
+ @_cache = IdentityMap.new
17
+ build_query
18
+ .map do |record, eager_data|
19
+ cache_and_init(record, with_associations_tree)
20
+ eager_data.zip(with_associations_tree.paths.map(&:last)).each do |eager_records, element|
21
+ eager_records.first.zip(eager_records.last).each do |eager_record|
22
+ add_to_cache(*eager_record, element)
23
+ end
24
+ end
25
+ record
26
+ end
27
+ end
28
+
29
+ def with_associations(*spec)
30
+ new_link.tap do |new_query_proxy|
31
+ new_query_proxy.with_associations_tree = with_associations_tree.clone
32
+ new_query_proxy.with_associations_tree.add_spec(spec)
33
+ end
34
+ end
35
+
36
+ def propagate_context(query_proxy)
37
+ super
38
+ query_proxy.instance_variable_set('@with_associations_tree', @with_associations_tree)
39
+ end
40
+
41
+ def with_associations_tree
42
+ @with_associations_tree ||= association_tree_class.new(model)
43
+ end
44
+
45
+ def association_tree_class
46
+ AssociationTree
47
+ end
48
+
49
+ def with_associations_tree=(tree)
50
+ @with_associations_tree = tree
51
+ end
52
+
53
+ def first
54
+ (query.clause?(:order) ? self : order(order_property)).limit(1).to_a.first
55
+ end
56
+
57
+ private
58
+
59
+ def add_to_cache(rel, node, element)
60
+ direction = element.association.direction
61
+ node = cache_and_init(node, element)
62
+ if rel.is_a?(Neo4j::ActiveRel)
63
+ rel.instance_variable_set(direction == :in ? '@from_node' : '@to_node', node)
64
+ end
65
+ @_cache[direction == :out ? rel.start_node_neo_id : rel.end_node_neo_id]
66
+ .association_proxy(element.name).add_to_cache(node, rel)
67
+ end
68
+
69
+ def init_associations(node, element)
70
+ element.each_key { |key| node.association_proxy(key).init_cache }
71
+ node.association_proxy(element.name).init_cache if element.rel_length == ''
72
+ end
73
+
74
+ def cache_and_init(node, element)
75
+ @_cache.add(node).tap { |n| init_associations(n, element) }
76
+ end
77
+
78
+ def with_associations_return_clause
79
+ path_names.map { |n| var(n, :collection, &:itself) }.join(',')
80
+ end
81
+
82
+ def var(*parts)
83
+ yield(escape(parts.compact.join('_')))
84
+ end
85
+
86
+ # In neo4j version 2.1.8 this fails due to a bug:
87
+ # MATCH (`n`) WITH `n` RETURN `n`
88
+ # but this
89
+ # MATCH (`n`) WITH n RETURN `n`
90
+ # and this
91
+ # MATCH (`n`) WITH `n` AS `n` RETURN `n`
92
+ # does not
93
+ def var_fix(*var)
94
+ var(*var, &method(:as_alias))
95
+ end
96
+
97
+ def as_alias(var)
98
+ "#{var} AS #{var}"
99
+ end
100
+
101
+ def escape(s)
102
+ "`#{s}`"
103
+ end
104
+
105
+ def path_name(path)
106
+ path.map(&:name).join('.')
107
+ end
108
+
109
+ def path_names
110
+ with_associations_tree.paths.map { |path| path_name(path) }
111
+ end
112
+
113
+ def build_query
114
+ before_pluck(query_from_association_tree).pluck(identity, "[#{with_associations_return_clause}]")
115
+ end
116
+
117
+ def before_pluck(query)
118
+ query_from_chain(@order_chain, query, identity)
119
+ end
120
+
121
+ def query_from_association_tree
122
+ previous_with_vars = []
123
+ with_associations_tree.paths.inject(query_as(identity).with(ensure_distinct(identity))) do |query, path|
124
+ with_association_query_part(query, path, previous_with_vars).tap do
125
+ previous_with_vars << var_fix(path_name(path), :collection)
126
+ end
127
+ end
128
+ end
129
+
130
+ def with_association_query_part(base_query, path, previous_with_vars)
131
+ optional_match_with_where(base_query, path, previous_with_vars)
132
+ .with(identity,
133
+ "[#{relationship_collection(path)}, collect(#{escape path_name(path)})] "\
134
+ "AS #{escape("#{path_name(path)}_collection")}",
135
+ *previous_with_vars)
136
+ end
137
+
138
+ def relationship_collection(path)
139
+ path.last.rel_length ? "collect(last(relationships(#{escape("#{path_name(path)}_path")})))" : "collect(#{escape("#{path_name(path)}_rel")})"
140
+ end
141
+
142
+ def optional_match_with_where(base_query, path, _)
143
+ path
144
+ .each_with_index.map { |_, index| path[0..index] }
145
+ .inject(optional_match(base_query, path)) do |query, path_prefix|
146
+ query.where(path_prefix.last.association.target_where_clause(escape(path_name(path_prefix))))
147
+ end
148
+ end
149
+
150
+ def optional_match(base_query, path)
151
+ start_path = "#{escape("#{path_name(path)}_path")}=(#{identity})"
152
+ base_query.optional_match(
153
+ "#{start_path}#{path.each_with_index.map do |element, index|
154
+ relationship_part(element.association, path_name(path[0..index]), element.rel_length)
155
+ end.join}"
156
+ )
157
+ end
158
+
159
+ def relationship_part(association, path_name, rel_length)
160
+ if rel_length
161
+ rel_name = nil
162
+ length = {max: rel_length}
163
+ else
164
+ rel_name = escape("#{path_name}_rel")
165
+ length = nil
166
+ end
167
+ "#{association.arrow_cypher(rel_name, {}, false, false, length)}(#{escape(path_name)})"
168
+ end
169
+
170
+ def chain
171
+ @order_chain = @chain.select { |link| link.clause == :order } unless with_associations_tree.empty?
172
+ @chain
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,75 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ module QueryProxyEagerLoading
5
+ class AssociationTree < Hash
6
+ attr_accessor :model, :name, :association, :path, :rel_length
7
+
8
+ def initialize(model, name = nil, rel_length = nil)
9
+ super()
10
+ self.model = name ? target_class(model, name) : model
11
+ self.name = name
12
+ self.association = name ? model.associations[name] : nil
13
+ self.rel_length = rel_length
14
+ end
15
+
16
+ def clone
17
+ super.tap { |copy| copy.each { |key, value| copy[key] = value.clone } }
18
+ end
19
+
20
+ def add_spec(spec)
21
+ fail_spec(spec) unless model
22
+
23
+ case spec
24
+ when nil
25
+ nil
26
+ when Array
27
+ spec.each(&method(:add_spec))
28
+ when Hash
29
+ process_hash(spec)
30
+ when String
31
+ process_string(spec)
32
+ else
33
+ add_key(spec)
34
+ end
35
+ end
36
+
37
+ def fail_spec(spec)
38
+ fail "Cannot eager load \"past\" a polymorphic association. \
39
+ (Since the association can return multiple models, we don't how to handle the \"#{spec}\" association.)"
40
+ end
41
+
42
+ def paths(*prefix)
43
+ values.flat_map { |v| [[*prefix, v]] + v.paths(*prefix, v) }
44
+ end
45
+
46
+ def process_hash(spec)
47
+ spec.each { |key, value| add_nested(key, value) }
48
+ end
49
+
50
+ def add_key(key, length = nil)
51
+ self[key] ||= self.class.new(model, key, length)
52
+ end
53
+
54
+ def add_nested(key, value, length = nil)
55
+ add_key(key, length).add_spec(value)
56
+ end
57
+
58
+ def process_string(str)
59
+ head, rest = str.split('.', 2)
60
+ k, length = head.split('*', -2)
61
+ add_nested(k.to_sym, rest, length)
62
+ end
63
+
64
+ private
65
+
66
+ def target_class(model, key)
67
+ association = model.associations[key]
68
+ fail "Invalid association: #{[*path, key].join('.')}" unless association
69
+ model.associations[key].target_class
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,110 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ # Methods related to returning nodes and rels from QueryProxy
5
+ module QueryProxyEnumerable
6
+ include Enumerable
7
+
8
+ # Just like every other <tt>each</tt> but it allows for optional params to support the versions that also return relationships.
9
+ # The <tt>node</tt> and <tt>rel</tt> params are typically used by those other methods but there's nothing stopping you from
10
+ # using `your_node.each(true, true)` instead of `your_node.each_with_rel`.
11
+ # @return [Enumerable] An enumerable containing some combination of nodes and rels.
12
+ def each(node = true, rel = nil, &block)
13
+ result(node, rel).each(&block)
14
+ end
15
+
16
+ def result(node = true, rel = nil)
17
+ return [].freeze if unpersisted_start_object?
18
+
19
+ @result_cache ||= {}
20
+ return result_cache_for(node, rel) if result_cache?(node, rel)
21
+
22
+ result = pluck_vars(node, rel)
23
+ set_instance_caches(result, node, rel)
24
+
25
+ @result_cache[[node, rel]] ||= result
26
+ end
27
+
28
+ def result_cache?(node = true, rel = nil)
29
+ !!result_cache_for(node, rel)
30
+ end
31
+
32
+ def result_cache_for(node = true, rel = nil)
33
+ (@result_cache || {})[[node, rel]]
34
+ end
35
+
36
+ def fetch_result_cache
37
+ @result_cache ||= yield
38
+ end
39
+
40
+ # When called at the end of a QueryProxy chain, it will return the resultant relationship objects intead of nodes.
41
+ # For example, to return the relationship between a given student and their lessons:
42
+ #
43
+ # .. code-block:: ruby
44
+ #
45
+ # student.lessons.each_rel do |rel|
46
+ #
47
+ # @return [Enumerable] An enumerable containing any number of applicable relationship objects.
48
+ def each_rel(&block)
49
+ block_given? ? each(false, true, &block) : to_enum(:each, false, true)
50
+ end
51
+
52
+ # When called at the end of a QueryProxy chain, it will return the nodes and relationships of the last link.
53
+ # For example, to return a lesson and each relationship to a given student:
54
+ #
55
+ # .. code-block:: ruby
56
+ #
57
+ # student.lessons.each_with_rel do |lesson, rel|
58
+ def each_with_rel(&block)
59
+ block_given? ? each(true, true, &block) : to_enum(:each, true, true)
60
+ end
61
+
62
+ # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
63
+ # would be comparing the QueryProxy objects, not the lessons themselves.
64
+ def ==(other)
65
+ self.to_a == other
66
+ end
67
+
68
+ # For getting variables which have been defined as part of the association chain
69
+ def pluck(*args)
70
+ transformable_attributes = (model ? model.attribute_names : []) + %w(uuid neo_id)
71
+ arg_list = args.map do |arg|
72
+ arg = Neo4j::ActiveNode::Query::QueryProxy::Link.converted_key(model, arg)
73
+ if transformable_attributes.include?(arg.to_s)
74
+ {identity => arg}
75
+ else
76
+ arg
77
+ end
78
+ end
79
+
80
+ self.query.pluck(*arg_list)
81
+ end
82
+
83
+ protected
84
+
85
+ def ensure_distinct(node, force = false)
86
+ @distinct || force ? "DISTINCT(#{node})" : node
87
+ end
88
+
89
+ private
90
+
91
+ def pluck_vars(node, rel)
92
+ vars = []
93
+ vars << ensure_distinct(identity) if node
94
+ vars << @rel_var if rel
95
+ pluck(*vars)
96
+ end
97
+
98
+ def set_instance_caches(instance, node, rel)
99
+ instance.each do |object|
100
+ object.instance_variable_set('@source_query_proxy', self)
101
+ object.instance_variable_set('@source_proxy_result_cache', instance)
102
+ if node && rel && object.last.is_a?(Neo4j::ActiveRel)
103
+ object.last.instance_variable_set(association.direction == :in ? '@from_node' : '@to_node', object.first)
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,19 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ module QueryProxyFindInBatches
5
+ def find_in_batches(options = {})
6
+ query.return(identity).find_in_batches(identity, @model.primary_key, options) do |batch|
7
+ yield batch.map(&identity)
8
+ end
9
+ end
10
+
11
+ def find_each(options = {})
12
+ query.return(identity).find_each(identity, @model.primary_key, options) do |result|
13
+ yield result.send(identity)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,139 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ module Query
4
+ class QueryProxy
5
+ class Link
6
+ attr_reader :clause
7
+
8
+ def initialize(clause, arg, args = [])
9
+ @clause = clause
10
+ @arg = arg
11
+ @args = args
12
+ end
13
+
14
+ def args(var, rel_var)
15
+ if @arg.respond_to?(:call)
16
+ @arg.call(var, rel_var)
17
+ else
18
+ [@arg] + @args
19
+ end
20
+ end
21
+
22
+ class << self
23
+ def for_clause(clause, arg, model, *args)
24
+ method_to_call = "for_#{clause}_clause"
25
+
26
+ send(method_to_call, arg, model, *args)
27
+ end
28
+
29
+ def for_where_clause(arg, model, *args)
30
+ node_num = 1
31
+ result = []
32
+ if arg.is_a?(Hash)
33
+ arg.each do |key, value|
34
+ if model && model.association?(key)
35
+ result += for_association(key, value, "n#{node_num}", model)
36
+ node_num += 1
37
+ else
38
+ result << new_for_key_and_value(model, key, value)
39
+ end
40
+ end
41
+ elsif arg.is_a?(String)
42
+ result << new(:where, arg, args)
43
+ end
44
+ result
45
+ end
46
+ alias for_node_where_clause for_where_clause
47
+
48
+ def for_where_not_clause(*args)
49
+ for_where_clause(*args).each do |link|
50
+ link.instance_variable_set('@clause', :where_not)
51
+ end
52
+ end
53
+
54
+ def new_for_key_and_value(model, key, value)
55
+ key = converted_key(model, key)
56
+
57
+ val = if !model
58
+ value
59
+ elsif key == model.id_property_name && value.is_a?(Neo4j::ActiveNode)
60
+ value.id
61
+ else
62
+ converted_value(model, key, value)
63
+ end
64
+
65
+ new(:where, ->(v, _) { {v => {key => val}} })
66
+ end
67
+
68
+ def for_association(name, value, n_string, model)
69
+ neo_id = value.try(:neo_id) || value
70
+ fail ArgumentError, "Invalid value for '#{name}' condition" if not neo_id.is_a?(Integer)
71
+
72
+ [
73
+ new(:match, ->(v, _) { "(#{v})#{model.associations[name].arrow_cypher}(#{n_string})" }),
74
+ new(:where, ->(_, _) { {"ID(#{n_string})" => neo_id.to_i} })
75
+ ]
76
+ end
77
+
78
+ # We don't accept strings here. If you want to use a string, just use where.
79
+ def for_rel_where_clause(arg, _, association)
80
+ arg.each_with_object([]) do |(key, value), result|
81
+ rel_class = association.relationship_class if association.relationship_class
82
+ val = rel_class ? converted_value(rel_class, key, value) : value
83
+ result << new(:where, ->(_, rel_var) { {rel_var => {key => val}} })
84
+ end
85
+ end
86
+
87
+ def for_rel_where_not_clause(*args)
88
+ for_rel_where_clause(*args).each do |link|
89
+ link.instance_variable_set('@clause', :where_not)
90
+ end
91
+ end
92
+
93
+ def for_rel_order_clause(arg, _)
94
+ [new(:order, ->(_, v) { arg.is_a?(String) ? arg : {v => arg} })]
95
+ end
96
+
97
+ def for_order_clause(arg, model)
98
+ [new(:order, ->(v, _) { arg.is_a?(String) ? arg : {v => converted_keys(model, arg)} })]
99
+ end
100
+
101
+ def for_args(model, clause, args, association = nil)
102
+ if [:where, :where_not].include?(clause) && args[0].is_a?(String) # Better way?
103
+ [for_arg(model, clause, args[0], *args[1..-1])]
104
+ elsif [:rel_where, :rel_where_not].include?(clause)
105
+ args.map { |arg| for_arg(model, clause, arg, association) }
106
+ else
107
+ args.map { |arg| for_arg(model, clause, arg) }
108
+ end
109
+ end
110
+
111
+ def for_arg(model, clause, arg, *args)
112
+ default = [Link.new(clause, arg, *args)]
113
+
114
+ Link.for_clause(clause, arg, model, *args) || default
115
+ rescue NoMethodError
116
+ default
117
+ end
118
+
119
+ def converted_keys(model, arg)
120
+ arg.is_a?(Hash) ? Hash[arg.map { |key, value| [converted_key(model, key), value] }] : arg
121
+ end
122
+
123
+ def converted_key(model, key)
124
+ if key.to_sym == :id
125
+ model ? model.id_property_name : :uuid
126
+ else
127
+ key
128
+ end
129
+ end
130
+
131
+ def converted_value(model, key, value)
132
+ model.declared_properties.value_for_where(key, value)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end