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,187 @@
1
+ module Neo4j::ActiveNode
2
+ # This module makes it possible to use other IDs than the build it neo4j id (neo_id)
3
+ #
4
+ # @example using generated UUIDs
5
+ # class Person
6
+ # include Neo4j::ActiveNode
7
+ # # creates a 'secret' neo4j property my_uuid which will be used as primary key
8
+ # id_property :my_uuid, auto: :uuid
9
+ # end
10
+ #
11
+ # @example using user defined ids
12
+ # class Person
13
+ # include Neo4j::ActiveNode
14
+ # property :title
15
+ # validates :title, :presence => true
16
+ # id_property :title_id, on: :title_to_url
17
+ #
18
+ # def title_to_url
19
+ # self.title.urlize # uses https://github.com/cheef/string-urlize gem
20
+ # end
21
+ # end
22
+ #
23
+ # @example using already exsting ids that you don't want a constraint added to
24
+ # class Person
25
+ # include Neo4j::ActiveNode
26
+ # property :title
27
+ # validates :title, :presence => true
28
+ # id_property :id, on: :id_builder, constraint: false
29
+ #
30
+ # def id_builder
31
+ # # only need to fill this out if you're gonna write to the db
32
+ # end
33
+ # end
34
+ #
35
+ module IdProperty
36
+ extend ActiveSupport::Concern
37
+ include Accessor
38
+
39
+ module TypeMethods
40
+ def define_id_methods(clazz, name, conf)
41
+ validate_conf!(conf)
42
+
43
+ if conf[:on]
44
+ define_custom_method(clazz, name, conf[:on])
45
+ elsif conf[:auto]
46
+ define_uuid_method(clazz, name)
47
+ elsif conf.empty?
48
+ define_property_method(clazz, name)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def validate_conf!(conf)
55
+ fail "Expected a Hash, got #{conf.class} (#{conf}) for id_property" if !conf.is_a?(Hash)
56
+
57
+ return if conf[:on]
58
+
59
+ if conf[:auto]
60
+ fail "only :uuid auto id_property allowed, got #{conf[:auto]}" if conf[:auto] != :uuid
61
+ return
62
+ end
63
+
64
+ return if conf.empty?
65
+
66
+ fail "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
67
+ end
68
+
69
+ def define_property_method(clazz, name)
70
+ clear_methods(clazz, name)
71
+
72
+ clazz.module_eval(%(
73
+ def id
74
+ _persisted_obj ? #{name.to_sym == :id ? 'attribute(\'id\')' : name} : nil
75
+ end
76
+
77
+ property :#{name}
78
+ ), __FILE__, __LINE__)
79
+ end
80
+
81
+
82
+ def define_uuid_method(clazz, name)
83
+ clear_methods(clazz, name)
84
+
85
+ clazz.module_eval(%(
86
+ default_property :#{name} do
87
+ ::SecureRandom.uuid
88
+ end
89
+
90
+ def #{name}
91
+ default_property_value
92
+ end
93
+
94
+ alias_method :id, :#{name}
95
+ ), __FILE__, __LINE__)
96
+ end
97
+
98
+ def define_custom_method(clazz, name, on)
99
+ clear_methods(clazz, name)
100
+
101
+ clazz.module_eval(%{
102
+ default_property :#{name} do |instance|
103
+ raise "Specifying custom id_property #{name} on non-existent method #{on}" unless instance.respond_to?(:#{on})
104
+ instance.#{on}
105
+ end
106
+
107
+ def #{name}
108
+ default_property_value
109
+ end
110
+
111
+ alias_method :id, :#{name}
112
+ }, __FILE__, __LINE__)
113
+ end
114
+
115
+ def clear_methods(clazz, name)
116
+ clazz.module_eval(%(undef_method :#{name}), __FILE__, __LINE__) if clazz.method_defined?(name)
117
+ clazz.module_eval(%(undef_property :#{name}), __FILE__, __LINE__) if clazz.attribute_names.include?(name.to_s)
118
+ end
119
+
120
+ extend self
121
+ end
122
+
123
+
124
+ module ClassMethods
125
+ attr_accessor :manual_id_property
126
+
127
+ def find_by_neo_id(id)
128
+ Neo4j::Node.load(id)
129
+ end
130
+
131
+ def find_by_id(id)
132
+ all.where(id_property_name => id).first
133
+ end
134
+
135
+ def find_by_ids(ids)
136
+ all.where(id_property_name => ids).to_a
137
+ end
138
+
139
+ def id_property(name, conf = {})
140
+ self.manual_id_property = true
141
+ Neo4j::Session.on_next_session_available do |_|
142
+ @id_property_info = {name: name, type: conf}
143
+ TypeMethods.define_id_methods(self, name, conf)
144
+ constraint(name, type: :unique) unless conf[:constraint] == false
145
+ end
146
+ end
147
+
148
+ # rubocop:disable Style/PredicateName
149
+ def has_id_property?
150
+ ActiveSupport::Deprecation.warn 'has_id_property? is deprecated and may be removed from future releases, use id_property? instead.', caller
151
+
152
+ id_property?
153
+ end
154
+ # rubocop:enable Style/PredicateName
155
+
156
+ def id_property?
157
+ id_property_info && !id_property_info.empty?
158
+ end
159
+
160
+ def id_property_info
161
+ @id_property_info ||= {}
162
+ end
163
+
164
+ def id_property_name
165
+ id_property_info[:name]
166
+ end
167
+
168
+ def manual_id_property?
169
+ !!manual_id_property
170
+ end
171
+
172
+ alias_method :primary_key, :id_property_name
173
+
174
+ private
175
+
176
+ def id_property_constraint(name)
177
+ if id_property?
178
+ unless mapped_label.uniqueness_constraints[:property_keys].include?([name])
179
+ # Neo4j Embedded throws a crazy error when a constraint can't be dropped
180
+ drop_constraint(id_property_name, type: :unique) if constraint?(mapped_label_name, id_property_name)
181
+ end
182
+ end
183
+ rescue Neo4j::Server::CypherResponse::ResponseError, Java::OrgNeo4jCypher::CypherExecutionException
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,21 @@
1
+ module Neo4j::ActiveNode::Initialize
2
+ extend ActiveSupport::Concern
3
+ include Neo4j::Shared::Initialize
4
+
5
+ attr_reader :called_by
6
+
7
+ # called when loading the node from the database
8
+ # @param [Neo4j::Node] persisted_node the node this class wraps
9
+ # @param [Hash] properties of the persisted node.
10
+ def init_on_load(persisted_node, properties)
11
+ self.class.extract_association_attributes!(properties)
12
+ @_persisted_obj = persisted_node
13
+ changed_attributes && changed_attributes.clear
14
+ @attributes = convert_and_assign_attributes(properties)
15
+ end
16
+
17
+ def init_on_reload(reloaded)
18
+ @attributes = nil
19
+ init_on_load(reloaded, reloaded.props)
20
+ end
21
+ end
@@ -0,0 +1,87 @@
1
+ module Neo4j::ActiveNode::Labels
2
+ module Index
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ extend Forwardable
7
+
8
+ def_delegators :declared_properties, :indexed_properties
9
+
10
+ # Creates a Neo4j index on given property
11
+ #
12
+ # This can also be done on the property directly, see Neo4j::ActiveNode::Property::ClassMethods#property.
13
+ #
14
+ # @param [Symbol] property the property we want a Neo4j index on
15
+ #
16
+ # @example
17
+ # class Person
18
+ # include Neo4j::ActiveNode
19
+ # property :name
20
+ # index :name
21
+ # end
22
+ def index(property)
23
+ Neo4j::Session.on_next_session_available do |_|
24
+ declared_properties.index_or_fail!(property, id_property_name)
25
+ schema_create_operation(:index, property)
26
+ end
27
+ end
28
+
29
+ # Creates a neo4j constraint on this class for given property
30
+ #
31
+ # @example
32
+ # Person.constraint :name, type: :unique
33
+ def constraint(property, constraints = {type: :unique})
34
+ Neo4j::Session.on_next_session_available do
35
+ declared_properties.constraint_or_fail!(property, id_property_name)
36
+ schema_create_operation(:constraint, property, constraints)
37
+ end
38
+ end
39
+
40
+ # @param [Symbol] property The name of the property index to be dropped
41
+ def drop_index(property, options = {})
42
+ Neo4j::Session.on_next_session_available do
43
+ declared_properties[property].unindex! if declared_properties[property]
44
+ schema_drop_operation(:index, property, options)
45
+ end
46
+ end
47
+
48
+ # @param [Symbol] property The name of the property constraint to be dropped
49
+ # @param [Hash] constraint The constraint type to be dropped.
50
+ def drop_constraint(property, constraint = {type: :unique})
51
+ Neo4j::Session.on_next_session_available do
52
+ declared_properties[property].unconstraint! if declared_properties[property]
53
+ schema_drop_operation(:constraint, property, constraint)
54
+ end
55
+ end
56
+
57
+ def index?(property)
58
+ mapped_label.indexes[:property_keys].include?([property])
59
+ end
60
+
61
+ def constraint?(property)
62
+ mapped_label.unique_constraints[:property_keys].include?([property])
63
+ end
64
+
65
+ private
66
+
67
+ def schema_create_operation(type, property, options = {})
68
+ new_schema_class(type, property, options).create!
69
+ end
70
+
71
+ def schema_drop_operation(type, property, options = {})
72
+ new_schema_class(type, property, options).drop!
73
+ end
74
+
75
+ def new_schema_class(type, property, options)
76
+ case type
77
+ when :index
78
+ Neo4j::Schema::ExactIndexOperation
79
+ when :constraint
80
+ Neo4j::Schema::UniqueConstraintOperation
81
+ else
82
+ fail "Unknown Schema Operation class #{type}"
83
+ end.new(mapped_label_name, property, options)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,21 @@
1
+ module Neo4j::ActiveNode::Labels
2
+ module Reloading
3
+ extend ActiveSupport::Concern
4
+
5
+ MODELS_TO_RELOAD = []
6
+
7
+ def self.reload_models!
8
+ MODELS_TO_RELOAD.each(&:constantize)
9
+ MODELS_TO_RELOAD.clear
10
+ end
11
+
12
+ module ClassMethods
13
+ def before_remove_const
14
+ associations.each_value(&:queue_model_refresh!)
15
+ MODELS_FOR_LABELS_CACHE.clear
16
+ WRAPPED_CLASSES.each { |c| MODELS_TO_RELOAD << c.name }
17
+ WRAPPED_CLASSES.clear
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,198 @@
1
+ module Neo4j
2
+ module ActiveNode
3
+ # Provides a mapping between neo4j labels and Ruby classes
4
+ module Labels
5
+ extend ActiveSupport::Concern
6
+ include Neo4j::ActiveNode::Labels::Index
7
+ include Neo4j::ActiveNode::Labels::Reloading
8
+
9
+ WRAPPED_CLASSES = []
10
+ MODELS_FOR_LABELS_CACHE = {}
11
+ MODELS_FOR_LABELS_CACHE.clear
12
+
13
+ included do |model|
14
+ Neo4j::ActiveNode::Labels.clear_wrapped_models
15
+
16
+ Neo4j::ActiveNode::Labels.add_wrapped_class(model) unless Neo4j::ActiveNode::Labels._wrapped_classes.include?(model)
17
+ end
18
+
19
+ class RecordNotFound < Neo4j::RecordNotFound; end
20
+
21
+ # @return the labels
22
+ # @see Neo4j-core
23
+ def labels
24
+ @_persisted_obj.labels
25
+ end
26
+
27
+ # this is handled by core, leaving it now for posterity
28
+ # def queried_labels
29
+ # self.class.query_as(:result).where("ID(result)" => self.neo_id).return("LABELS(result) as result_labels").first.result_labels.map(&:to_sym)
30
+ # end
31
+
32
+ # adds one or more labels
33
+ # @see Neo4j-core
34
+ def add_label(*label)
35
+ @_persisted_obj.add_label(*label)
36
+ end
37
+
38
+ # Removes one or more labels
39
+ # Be careful, don't remove the label representing the Ruby class.
40
+ # @see Neo4j-core
41
+ def remove_label(*label)
42
+ @_persisted_obj.remove_label(*label)
43
+ end
44
+
45
+ def self._wrapped_classes
46
+ WRAPPED_CLASSES
47
+ end
48
+
49
+ def self.add_wrapped_class(model)
50
+ _wrapped_classes << model
51
+ end
52
+
53
+ # Finds an appropriate matching model given a set of labels
54
+ # which are assigned to a node
55
+ def self.model_for_labels(labels)
56
+ return MODELS_FOR_LABELS_CACHE[labels] if MODELS_FOR_LABELS_CACHE[labels]
57
+
58
+ models = WRAPPED_CLASSES.select do |model|
59
+ (model.mapped_label_names - labels).size == 0
60
+ end
61
+
62
+ MODELS_FOR_LABELS_CACHE[labels] = models.max_by do |model|
63
+ (model.mapped_label_names & labels).size
64
+ end
65
+ end
66
+
67
+ def self.clear_wrapped_models
68
+ MODELS_FOR_LABELS_CACHE.clear
69
+ Neo4j::Node::Wrapper::CONSTANTS_FOR_LABELS_CACHE.clear
70
+ end
71
+
72
+ module ClassMethods
73
+ include Neo4j::ActiveNode::QueryMethods
74
+
75
+ delegate :update_all, to: :all
76
+
77
+ # Returns the object with the specified neo4j id.
78
+ # @param [String,Integer] id of node to find
79
+ def find(id)
80
+ map_id = proc { |object| object.respond_to?(:id) ? object.send(:id) : object }
81
+
82
+ result = find_by_id_or_ids(map_id, id)
83
+
84
+ fail RecordNotFound.new(
85
+ "Couldn't find #{name} with '#{id_property_name}'=#{id}",
86
+ name, id_property_name, id) if result.blank?
87
+ result.tap { |r| find_callbacks!(r) }
88
+ end
89
+
90
+ # Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.
91
+ # @param values Hash args of arguments to find
92
+ def find_by(values)
93
+ all.where(values).limit(1).query_as(:n).pluck(:n).first
94
+ end
95
+
96
+ # Like find_by, except that if no record is found, raises a RecordNotFound error.
97
+ def find_by!(values)
98
+ find_by(values) || fail(RecordNotFound, "#{self.query_as(:n).where(n: values).limit(1).to_cypher} returned no results")
99
+ end
100
+
101
+ # Deletes all nodes and connected relationships from Cypher.
102
+ def delete_all
103
+ self.neo4j_session._query("MATCH (n:`#{mapped_label_name}`) OPTIONAL MATCH (n)-[r]-() DELETE n,r")
104
+ self.neo4j_session._query("MATCH (n:`#{mapped_label_name}`) DELETE n")
105
+ end
106
+
107
+ # Returns each node to Ruby and calls `destroy`. Be careful, as this can be a very slow operation if you have many nodes. It will generate at least
108
+ # one database query per node in the database, more if callbacks require them.
109
+ def destroy_all
110
+ all.each(&:destroy)
111
+ end
112
+
113
+ # @return [Array{Symbol}] all the labels that this class has
114
+ def mapped_label_names
115
+ self.ancestors.find_all { |a| a.respond_to?(:mapped_label_name) }.map { |a| a.mapped_label_name.to_sym }
116
+ end
117
+
118
+ # @return [Symbol] the label that this class has which corresponds to a Ruby class
119
+ def mapped_label_name
120
+ @mapped_label_name || label_for_model
121
+ end
122
+
123
+ # @return [Neo4j::Label] the label for this class
124
+ def mapped_label
125
+ Neo4j::Label.create(mapped_label_name)
126
+ end
127
+
128
+ def base_class
129
+ unless self < Neo4j::ActiveNode
130
+ fail "#{name} doesn't belong in a hierarchy descending from ActiveNode"
131
+ end
132
+
133
+ if superclass == Object
134
+ self
135
+ else
136
+ superclass.base_class
137
+ end
138
+ end
139
+
140
+ protected
141
+
142
+ def mapped_labels
143
+ mapped_label_names.map { |label_name| Neo4j::Label.create(label_name) }
144
+ end
145
+
146
+ def mapped_label_name=(name)
147
+ @mapped_label_name = name.to_sym
148
+ end
149
+
150
+ # rubocop:disable Style/AccessorMethodName
151
+ def set_mapped_label_name(name)
152
+ ActiveSupport::Deprecation.warn 'set_mapped_label_name is deprecated, use self.mapped_label_name= instead.', caller
153
+
154
+ self.mapped_label_name = name
155
+ end
156
+ # rubocop:enable Style/AccessorMethodName
157
+
158
+ private
159
+
160
+ def find_by_id_or_ids(map_id, id)
161
+ if id.is_a?(Array)
162
+ find_by_ids(id.map(&map_id))
163
+ else
164
+ find_by_id(map_id.call(id))
165
+ end
166
+ end
167
+
168
+ def find_callbacks!(result)
169
+ case result
170
+ when Neo4j::ActiveNode
171
+ result.run_callbacks(:find)
172
+ when Array
173
+ result.each { |r| find_callbacks!(r) }
174
+ else
175
+ result
176
+ end
177
+ end
178
+
179
+ def label_for_model
180
+ (self.name.nil? ? object_id.to_s.to_sym : decorated_label_name)
181
+ end
182
+
183
+ def decorated_label_name
184
+ name = case Neo4j::Config[:module_handling]
185
+ when :demodulize
186
+ self.name.demodulize
187
+ when Proc
188
+ Neo4j::Config[:module_handling].call self.name
189
+ else
190
+ self.name
191
+ end
192
+
193
+ name.to_sym
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,52 @@
1
+ require 'active_support/inflector'
2
+
3
+ class Neo4j::Node
4
+ # The wrapping process is what transforms a raw CypherNode or EmbeddedNode from Neo4j::Core into a healthy ActiveNode (or ActiveRel) object.
5
+ module Wrapper
6
+ # this is a plugin in the neo4j-core so that the Ruby wrapper will be wrapped around the Neo4j::Node objects
7
+ def wrapper
8
+ found_class = class_to_wrap
9
+ return self if not found_class
10
+
11
+ found_class.new.tap do |wrapped_node|
12
+ wrapped_node.init_on_load(self, self.props)
13
+ end
14
+ end
15
+
16
+ def class_to_wrap
17
+ load_classes_from_labels
18
+ Neo4j::ActiveNode::Labels.model_for_labels(labels).tap do |model_class|
19
+ Neo4j::Node::Wrapper.populate_constants_for_labels_cache(model_class, labels)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def load_classes_from_labels
26
+ labels.each { |label| Neo4j::Node::Wrapper.constant_for_label(label) }
27
+ end
28
+
29
+ # Only load classes once for performance
30
+ CONSTANTS_FOR_LABELS_CACHE = {}
31
+
32
+ def self.constant_for_label(label)
33
+ CONSTANTS_FOR_LABELS_CACHE[label] || CONSTANTS_FOR_LABELS_CACHE[label] = constantized_label(label)
34
+ end
35
+
36
+ def self.constantized_label(label)
37
+ "#{association_model_namespace}::#{label}".constantize
38
+ rescue NameError
39
+ nil
40
+ end
41
+
42
+ def self.populate_constants_for_labels_cache(model_class, labels)
43
+ labels.each do |label|
44
+ CONSTANTS_FOR_LABELS_CACHE[label] = model_class if CONSTANTS_FOR_LABELS_CACHE[label].nil?
45
+ end
46
+ end
47
+
48
+ def self.association_model_namespace
49
+ Neo4j::Config.association_model_namespace_string
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,82 @@
1
+ require 'orm_adapter'
2
+
3
+ module Neo4j
4
+ module ActiveNode
5
+ module ClassMethods
6
+ include OrmAdapter::ToAdapter
7
+ end
8
+
9
+ class OrmAdapter < ::OrmAdapter::Base
10
+ module ClassMethods
11
+ include ActiveModel::Callbacks
12
+ end
13
+
14
+ def column_names
15
+ klass._decl_props.keys
16
+ end
17
+
18
+ def i18n_scope
19
+ :neo4j
20
+ end
21
+
22
+ # Get an instance by id of the model
23
+ def get!(id)
24
+ klass.find(wrap_key(id)).tap do |node|
25
+ fail 'No record found' if node.nil?
26
+ end
27
+ end
28
+
29
+ # Get an instance by id of the model
30
+ def get(id)
31
+ klass.find_by(klass.id_property_name => wrap_key(id))
32
+ end
33
+
34
+ # Find the first instance matching conditions
35
+ def find_first(options = {})
36
+ conditions, order = extract_conditions!(options)
37
+ extract_id!(conditions)
38
+ order = hasherize_order(order)
39
+
40
+ result = klass.where(conditions)
41
+ result = result.order(order) unless order.empty?
42
+ result.first
43
+ end
44
+
45
+ # Find all models matching conditions
46
+ def find_all(options = {})
47
+ conditions, order, limit, offset = extract_conditions!(options)
48
+ extract_id!(conditions)
49
+ order = hasherize_order(order)
50
+
51
+ result = klass.where(conditions)
52
+ result = result.order(order) unless order.empty?
53
+ result = result.skip(offset) if offset
54
+ result = result.limit(limit) if limit
55
+ result.to_a
56
+ end
57
+
58
+ # Create a model using attributes
59
+ def create!(attributes = {})
60
+ klass.create!(attributes)
61
+ end
62
+
63
+ # @see OrmAdapter::Base#destroy
64
+ def destroy(object)
65
+ object.destroy && true if valid_object?(object)
66
+ end
67
+
68
+ private
69
+
70
+ def hasherize_order(order)
71
+ (order || []).map { |clause| Hash[*clause] }
72
+ end
73
+
74
+ def extract_id!(conditions)
75
+ id = conditions.delete(:id)
76
+ return if not id
77
+
78
+ conditions[klass.id_property_name.to_sym] = id
79
+ end
80
+ end
81
+ end
82
+ end