neo4j_legacy 7.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1357 -0
  3. data/CONTRIBUTORS +8 -0
  4. data/Gemfile +38 -0
  5. data/README.md +103 -0
  6. data/bin/neo4j-jars +33 -0
  7. data/bin/rake +17 -0
  8. data/config/locales/en.yml +5 -0
  9. data/config/neo4j/add_classnames.yml +1 -0
  10. data/config/neo4j/config.yml +35 -0
  11. data/lib/active_support/per_thread_registry.rb +1 -0
  12. data/lib/backports/action_controller/metal/strong_parameters.rb +672 -0
  13. data/lib/backports/active_model/forbidden_attributes_protection.rb +30 -0
  14. data/lib/backports/active_support/concern.rb +13 -0
  15. data/lib/backports/active_support/core_ext/module/attribute_accessors.rb +10 -0
  16. data/lib/backports/active_support/logger.rb +99 -0
  17. data/lib/backports/active_support/logger_silence.rb +27 -0
  18. data/lib/backports/active_support/logger_thread_safe_level.rb +32 -0
  19. data/lib/backports/active_support/per_thread_registry.rb +60 -0
  20. data/lib/backports.rb +4 -0
  21. data/lib/neo4j/active_node/callbacks.rb +8 -0
  22. data/lib/neo4j/active_node/dependent/association_methods.rb +48 -0
  23. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +50 -0
  24. data/lib/neo4j/active_node/dependent.rb +11 -0
  25. data/lib/neo4j/active_node/enum.rb +29 -0
  26. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
  27. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
  28. data/lib/neo4j/active_node/has_n/association.rb +280 -0
  29. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
  30. data/lib/neo4j/active_node/has_n.rb +532 -0
  31. data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
  32. data/lib/neo4j/active_node/id_property.rb +187 -0
  33. data/lib/neo4j/active_node/initialize.rb +21 -0
  34. data/lib/neo4j/active_node/labels/index.rb +87 -0
  35. data/lib/neo4j/active_node/labels/reloading.rb +21 -0
  36. data/lib/neo4j/active_node/labels.rb +198 -0
  37. data/lib/neo4j/active_node/node_wrapper.rb +52 -0
  38. data/lib/neo4j/active_node/orm_adapter.rb +82 -0
  39. data/lib/neo4j/active_node/persistence.rb +175 -0
  40. data/lib/neo4j/active_node/property.rb +60 -0
  41. data/lib/neo4j/active_node/query/query_proxy.rb +361 -0
  42. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +61 -0
  43. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +90 -0
  44. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
  45. data/lib/neo4j/active_node/query/query_proxy_link.rb +117 -0
  46. data/lib/neo4j/active_node/query/query_proxy_methods.rb +210 -0
  47. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +83 -0
  48. data/lib/neo4j/active_node/query.rb +76 -0
  49. data/lib/neo4j/active_node/query_methods.rb +65 -0
  50. data/lib/neo4j/active_node/reflection.rb +86 -0
  51. data/lib/neo4j/active_node/rels.rb +11 -0
  52. data/lib/neo4j/active_node/scope.rb +146 -0
  53. data/lib/neo4j/active_node/unpersisted.rb +48 -0
  54. data/lib/neo4j/active_node/validations.rb +59 -0
  55. data/lib/neo4j/active_node.rb +105 -0
  56. data/lib/neo4j/active_rel/callbacks.rb +15 -0
  57. data/lib/neo4j/active_rel/initialize.rb +28 -0
  58. data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
  59. data/lib/neo4j/active_rel/persistence.rb +114 -0
  60. data/lib/neo4j/active_rel/property.rb +95 -0
  61. data/lib/neo4j/active_rel/query.rb +95 -0
  62. data/lib/neo4j/active_rel/rel_wrapper.rb +22 -0
  63. data/lib/neo4j/active_rel/related_node.rb +83 -0
  64. data/lib/neo4j/active_rel/types.rb +82 -0
  65. data/lib/neo4j/active_rel/validations.rb +8 -0
  66. data/lib/neo4j/active_rel.rb +67 -0
  67. data/lib/neo4j/class_arguments.rb +39 -0
  68. data/lib/neo4j/config.rb +124 -0
  69. data/lib/neo4j/core/query.rb +22 -0
  70. data/lib/neo4j/errors.rb +28 -0
  71. data/lib/neo4j/migration.rb +127 -0
  72. data/lib/neo4j/paginated.rb +27 -0
  73. data/lib/neo4j/railtie.rb +169 -0
  74. data/lib/neo4j/schema/operation.rb +91 -0
  75. data/lib/neo4j/shared/attributes.rb +220 -0
  76. data/lib/neo4j/shared/callbacks.rb +64 -0
  77. data/lib/neo4j/shared/cypher.rb +37 -0
  78. data/lib/neo4j/shared/declared_properties.rb +204 -0
  79. data/lib/neo4j/shared/declared_property/index.rb +37 -0
  80. data/lib/neo4j/shared/declared_property.rb +118 -0
  81. data/lib/neo4j/shared/enum.rb +148 -0
  82. data/lib/neo4j/shared/filtered_hash.rb +79 -0
  83. data/lib/neo4j/shared/identity.rb +28 -0
  84. data/lib/neo4j/shared/initialize.rb +28 -0
  85. data/lib/neo4j/shared/marshal.rb +23 -0
  86. data/lib/neo4j/shared/mass_assignment.rb +58 -0
  87. data/lib/neo4j/shared/permitted_attributes.rb +28 -0
  88. data/lib/neo4j/shared/persistence.rb +231 -0
  89. data/lib/neo4j/shared/property.rb +220 -0
  90. data/lib/neo4j/shared/query_factory.rb +101 -0
  91. data/lib/neo4j/shared/rel_type_converters.rb +43 -0
  92. data/lib/neo4j/shared/serialized_properties.rb +30 -0
  93. data/lib/neo4j/shared/type_converters.rb +418 -0
  94. data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
  95. data/lib/neo4j/shared/typecaster.rb +53 -0
  96. data/lib/neo4j/shared/validations.rb +48 -0
  97. data/lib/neo4j/shared.rb +51 -0
  98. data/lib/neo4j/tasks/migration.rake +24 -0
  99. data/lib/neo4j/timestamps/created.rb +9 -0
  100. data/lib/neo4j/timestamps/updated.rb +9 -0
  101. data/lib/neo4j/timestamps.rb +11 -0
  102. data/lib/neo4j/type_converters.rb +7 -0
  103. data/lib/neo4j/version.rb +3 -0
  104. data/lib/neo4j/wrapper.rb +4 -0
  105. data/lib/neo4j.rb +96 -0
  106. data/lib/rails/generators/neo4j/model/model_generator.rb +86 -0
  107. data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
  108. data/lib/rails/generators/neo4j_generator.rb +67 -0
  109. data/neo4j.gemspec +43 -0
  110. metadata +389 -0
@@ -0,0 +1,220 @@
1
+ module Neo4j::Shared
2
+ module Property
3
+ extend ActiveSupport::Concern
4
+
5
+ include Neo4j::Shared::MassAssignment
6
+ include Neo4j::Shared::TypecastedAttributes
7
+ include ActiveModel::Dirty
8
+
9
+ class UndefinedPropertyError < Neo4j::Error; end
10
+ class MultiparameterAssignmentError < Neo4j::Error; end
11
+
12
+ attr_reader :_persisted_obj
13
+
14
+ def inspect
15
+ attribute_descriptions = inspect_attributes.map do |key, value|
16
+ "#{Neo4j::ANSI::CYAN}#{key}: #{Neo4j::ANSI::CLEAR}#{value.inspect}"
17
+ end.join(', ')
18
+
19
+ separator = ' ' unless attribute_descriptions.empty?
20
+ "#<#{Neo4j::ANSI::YELLOW}#{self.class.name}#{Neo4j::ANSI::CLEAR}#{separator}#{attribute_descriptions}>"
21
+ end
22
+
23
+ def initialize(attributes = nil)
24
+ attributes = process_attributes(attributes)
25
+ modded_attributes = inject_defaults!(attributes)
26
+ validate_attributes!(modded_attributes)
27
+ writer_method_props = extract_writer_methods!(modded_attributes)
28
+ send_props(writer_method_props)
29
+ @_persisted_obj = nil
30
+ end
31
+
32
+ def inject_defaults!(starting_props)
33
+ return starting_props if self.class.declared_properties.declared_property_defaults.empty?
34
+ self.class.declared_properties.inject_defaults!(self, starting_props || {})
35
+ end
36
+
37
+ def read_attribute(name)
38
+ respond_to?(name) ? send(name) : nil
39
+ end
40
+ alias_method :[], :read_attribute
41
+
42
+ def send_props(hash)
43
+ return hash if hash.blank?
44
+ hash.each { |key, value| send("#{key}=", value) }
45
+ end
46
+
47
+ def reload_properties!(properties)
48
+ @attributes = nil
49
+ convert_and_assign_attributes(properties)
50
+ end
51
+
52
+ private
53
+
54
+ # Changes attributes hash to remove relationship keys
55
+ # Raises an error if there are any keys left which haven't been defined as properties on the model
56
+ # TODO: use declared_properties instead of self.attributes
57
+ def validate_attributes!(attributes)
58
+ return attributes if attributes.blank?
59
+ invalid_properties = attributes.keys.map(&:to_s) - self.attributes.keys
60
+ invalid_properties.reject! { |name| self.respond_to?("#{name}=") }
61
+ fail UndefinedPropertyError, "Undefined properties: #{invalid_properties.join(',')}" if invalid_properties.size > 0
62
+ end
63
+
64
+ def extract_writer_methods!(attributes)
65
+ return attributes if attributes.blank?
66
+ {}.tap do |writer_method_props|
67
+ attributes.each_key do |key|
68
+ writer_method_props[key] = attributes.delete(key) if self.respond_to?("#{key}=")
69
+ end
70
+ end
71
+ end
72
+
73
+ DATE_KEY_REGEX = /\A([^\(]+)\((\d+)([if])\)$/
74
+ # Gives support for Rails date_select, datetime_select, time_select helpers.
75
+ def process_attributes(attributes = nil)
76
+ return attributes if attributes.blank?
77
+ multi_parameter_attributes = {}
78
+ new_attributes = {}
79
+ attributes.each_pair do |key, value|
80
+ if key.match(DATE_KEY_REGEX)
81
+ match = key.to_s.match(DATE_KEY_REGEX)
82
+ found_key = match[1]
83
+ index = match[2].to_i
84
+ (multi_parameter_attributes[found_key] ||= {})[index] = value.empty? ? nil : value.send("to_#{$3}")
85
+ else
86
+ new_attributes[key] = value
87
+ end
88
+ end
89
+
90
+ multi_parameter_attributes.empty? ? new_attributes : process_multiparameter_attributes(multi_parameter_attributes, new_attributes)
91
+ end
92
+
93
+ def process_multiparameter_attributes(multi_parameter_attributes, new_attributes)
94
+ multi_parameter_attributes.each_with_object(new_attributes) do |(key, values), attributes|
95
+ values = (values.keys.min..values.keys.max).map { |i| values[i] }
96
+ if (field = self.class.attributes[key.to_sym]).nil?
97
+ fail MultiparameterAssignmentError, "error on assignment #{values.inspect} to #{key}"
98
+ end
99
+
100
+ attributes[key] = instantiate_object(field, values)
101
+ end
102
+ end
103
+
104
+ def instantiate_object(field, values_with_empty_parameters)
105
+ return nil if values_with_empty_parameters.all?(&:nil?)
106
+ values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
107
+ klass = field.type
108
+ klass ? klass.new(*values) : values
109
+ end
110
+
111
+ module ClassMethods
112
+ extend Forwardable
113
+
114
+ def_delegators :declared_properties, :serialized_properties, :serialized_properties=, :serialize, :declared_property_defaults
115
+
116
+ # Defines a property on the class
117
+ #
118
+ # See active_attr gem for allowed options, e.g which type
119
+ # Notice, in Neo4j you don't have to declare properties before using them, see the neo4j-core api.
120
+ #
121
+ # @example Without type
122
+ # class Person
123
+ # # declare a property which can have any value
124
+ # property :name
125
+ # end
126
+ #
127
+ # @example With type and a default value
128
+ # class Person
129
+ # # declare a property which can have any value
130
+ # property :score, type: Integer, default: 0
131
+ # end
132
+ #
133
+ # @example With an index
134
+ # class Person
135
+ # # declare a property which can have any value
136
+ # property :name, index: :exact
137
+ # end
138
+ #
139
+ # @example With a constraint
140
+ # class Person
141
+ # # declare a property which can have any value
142
+ # property :name, constraint: :unique
143
+ # end
144
+ def property(name, options = {})
145
+ build_property(name, options) do |prop|
146
+ attribute(prop)
147
+ end
148
+ end
149
+
150
+ # @param [Symbol] name The property name
151
+ # @param [Neo4j::Shared::AttributeDefinition] attr_def A cloned AttributeDefinition to reuse
152
+ # @param [Hash] options An options hash to use in the new property definition
153
+ def inherit_property(name, attr_def, options = {})
154
+ build_property(name, options) do |prop_name|
155
+ attributes[prop_name] = attr_def
156
+ end
157
+ end
158
+
159
+ def build_property(name, options)
160
+ DeclaredProperty.new(name, options).tap do |prop|
161
+ prop.register
162
+ declared_properties.register(prop)
163
+ yield name
164
+ constraint_or_index(name, options)
165
+ end
166
+ end
167
+
168
+ def undef_property(name)
169
+ undef_constraint_or_index(name)
170
+ declared_properties.unregister(name)
171
+ attribute_methods(name).each { |method| undef_method(method) }
172
+ end
173
+
174
+ def declared_properties
175
+ @_declared_properties ||= DeclaredProperties.new(self)
176
+ end
177
+
178
+ # @return [Hash] A frozen hash of all model properties with nil values. It is used during node loading and prevents
179
+ # an extra call to a slow dependency method.
180
+ def attributes_nil_hash
181
+ declared_properties.attributes_nil_hash
182
+ end
183
+
184
+ def extract_association_attributes!(props)
185
+ props
186
+ end
187
+
188
+ private
189
+
190
+ def attribute!(name)
191
+ remove_instance_variable('@attribute_methods_generated') if instance_variable_defined?('@attribute_methods_generated')
192
+ define_attribute_methods([name]) unless attribute_names.include?(name)
193
+ attributes[name.to_s] = declared_properties[name]
194
+ define_method("#{name}=") do |value|
195
+ typecast_value = typecast_attribute(_attribute_typecaster(name), value)
196
+ send("#{name}_will_change!") unless typecast_value == read_attribute(name)
197
+ super(value)
198
+ end
199
+ end
200
+
201
+ def constraint_or_index(name, options)
202
+ # either constraint or index, do not set both
203
+ if options[:constraint]
204
+ fail "unknown constraint type #{options[:constraint]}, only :unique supported" if options[:constraint] != :unique
205
+ constraint(name, type: :unique)
206
+ elsif options[:index]
207
+ fail "unknown index type #{options[:index]}, only :exact supported" if options[:index] != :exact
208
+ index(name) if options[:index] == :exact
209
+ end
210
+ end
211
+
212
+ def undef_constraint_or_index(name)
213
+ prop = declared_properties[name]
214
+ return unless prop.index_or_constraint?
215
+ type = prop.constraint? ? :constraint : :index
216
+ send(:"drop_#{type}", name)
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,101 @@
1
+ module Neo4j::Shared
2
+ # Acts as a bridge between the node and rel models and Neo4j::Core::Query.
3
+ # If the object is persisted, it returns a query matching; otherwise, it returns a query creating it.
4
+ # This class does not execute queries, so it keeps no record of what identifiers have been set or what has happened in previous factories.
5
+ class QueryFactory
6
+ attr_reader :graph_object, :identifier
7
+
8
+ def initialize(graph_object, identifier)
9
+ @graph_object = graph_object
10
+ @identifier = identifier.to_sym
11
+ end
12
+
13
+ def self.create(graph_object, identifier)
14
+ factory_for(graph_object).new(graph_object, identifier)
15
+ end
16
+
17
+ def self.factory_for(graph_obj)
18
+ case
19
+ when graph_obj.respond_to?(:labels_for_create)
20
+ NodeQueryFactory
21
+ when graph_obj.respond_to?(:rel_type)
22
+ RelQueryFactory
23
+ else
24
+ fail "Unable to find factory for #{graph_obj}"
25
+ end
26
+ end
27
+
28
+ def query
29
+ graph_object.persisted? ? match_query : create_query
30
+ end
31
+
32
+ # @param [Neo4j::Core::Query] query An instance of Neo4j::Core::Query upon which methods will be chained.
33
+ def base_query=(query)
34
+ return if query.blank?
35
+ @base_query = query
36
+ end
37
+
38
+ def base_query
39
+ @base_query || Neo4j::Session.current.query
40
+ end
41
+
42
+ protected
43
+
44
+ def create_query
45
+ fail 'Abstract class, not implemented'
46
+ end
47
+
48
+ def match_query
49
+ base_query
50
+ .match(match_string).where("ID(#{identifier}) = {#{identifier_id}}")
51
+ .params(identifier_id.to_sym => graph_object.neo_id)
52
+ end
53
+
54
+ def identifier_id
55
+ @identifier_id ||= "#{identifier}_id"
56
+ end
57
+
58
+ def identifier_params
59
+ @identifier_params ||= "#{identifier}_params"
60
+ end
61
+ end
62
+
63
+ class NodeQueryFactory < QueryFactory
64
+ protected
65
+
66
+ def match_string
67
+ "(#{identifier})"
68
+ end
69
+
70
+ def create_query
71
+ return match_query if graph_object.persisted?
72
+ base_query.create(identifier => {graph_object.labels_for_create => graph_object.props_for_create})
73
+ end
74
+ end
75
+
76
+ class RelQueryFactory < QueryFactory
77
+ protected
78
+
79
+ def match_string
80
+ "(#{graph_object.from_node_identifier})-[#{identifier}]->()"
81
+ end
82
+
83
+ def create_query
84
+ return match_query if graph_object.persisted?
85
+ create_props, set_props = filtered_props
86
+ base_query.send(graph_object.create_method, query_string).break
87
+ .set(identifier => set_props)
88
+ .params(:"#{identifier}_create_props" => create_props)
89
+ end
90
+
91
+ private
92
+
93
+ def filtered_props
94
+ Neo4j::Shared::FilteredHash.new(graph_object.props_for_create, graph_object.creates_unique_option).filtered_base
95
+ end
96
+
97
+ def query_string
98
+ "(#{graph_object.from_node_identifier})-[#{identifier}:`#{graph_object.type}` {#{identifier}_create_props}]->(#{graph_object.to_node_identifier})"
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,43 @@
1
+ module Neo4j::Shared
2
+ # This module controls changes to relationship type based on Neo4j::Config.transform_rel_type.
3
+ # It's used whenever a rel type is automatically determined based on ActiveRel model name or
4
+ # association type.
5
+ module RelTypeConverters
6
+ def decorated_rel_type(type)
7
+ @decorated_rel_type ||= Neo4j::Shared::RelTypeConverters.decorated_rel_type(type)
8
+ end
9
+
10
+ class << self
11
+ # Determines how relationship types should look when inferred based on association or ActiveRel model name.
12
+ # With the exception of `:none`, all options will call `underscore`, so `ThisClass` becomes `this_class`, with capitalization
13
+ # determined by the specific option passed.
14
+ # Valid options:
15
+ # * :upcase - `:this_class`, `ThisClass`, `thiS_claSs` (if you don't like yourself) becomes `THIS_CLASS`
16
+ # * :downcase - same as above, only... downcased.
17
+ # * :legacy - downcases and prepends `#`, so ThisClass becomes `#this_class`
18
+ # * :none - uses the string version of whatever is passed with no modifications
19
+ def rel_transformer
20
+ @rel_transformer ||= Neo4j::Config[:transform_rel_type].nil? ? :upcase : Neo4j::Config[:transform_rel_type]
21
+ end
22
+
23
+ # @param [String,Symbol] type The raw string or symbol to be used as the basis of the relationship type
24
+ # @return [String] A string that conforms to the set rel type conversion setting.
25
+ def decorated_rel_type(type)
26
+ type = type.to_s
27
+ decorated_type = case rel_transformer
28
+ when :upcase
29
+ type.underscore.upcase
30
+ when :downcase
31
+ type.underscore.downcase
32
+ when :legacy
33
+ "##{type.underscore.downcase}"
34
+ when :none
35
+ type
36
+ else
37
+ type.underscore.upcase
38
+ end
39
+ decorated_type.tap { |s| s.gsub!('/', '::') if type.include?('::') }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ module Neo4j::Shared
2
+ # This module adds the `serialize` class method. It lets you store hashes and arrays in Neo4j properties.
3
+ # Be aware that you won't be able to search within serialized properties and stuff use indexes. If you do a regex search for portion of a string
4
+ # property, the search happens in Cypher and you may take a performance hit.
5
+ #
6
+ # See type_converters.rb for the serialization process.
7
+ module SerializedProperties
8
+ extend ActiveSupport::Concern
9
+
10
+ def serialized_properties
11
+ self.class.serialized_properties
12
+ end
13
+
14
+ def serializable_hash(*args)
15
+ super.merge(id: id)
16
+ end
17
+
18
+
19
+ module ClassMethods
20
+ def inherited(other)
21
+ inherit_serialized_properties(other) if self.respond_to?(:serialized_properties)
22
+ super
23
+ end
24
+
25
+ def inherit_serialized_properties(other)
26
+ other.serialized_properties = self.serialized_properties
27
+ end
28
+ end
29
+ end
30
+ end