neo4j 5.1.5 → 5.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee39f89dbeb6c4cbb84e138646bd14387a58a3e1
4
- data.tar.gz: d3db82c3713b3be64ed389f9e249c95064d68491
3
+ metadata.gz: cdc33103cf05e1ec6a124c615303f0fcb7ff0760
4
+ data.tar.gz: 679ae2889ebbe49d6083fe9d471508996a2e6750
5
5
  SHA512:
6
- metadata.gz: 7761cd3c739a85440143ebf2c0063b797e874a83002639a6fecebc35b24f04013cfda55a798b344fbb5bbccfc85a287340773ca238f3373400cf2488e601ade4
7
- data.tar.gz: 779db34b9d23809daec8ba37bee90ba6207869016f29928b52b7e1f1a5a6b687ff644d70c15ed14a86fcc747047d9b7062a87e57ea33fb0ef0589b7fd2bb0fac
6
+ metadata.gz: 1b770454c98281fded4132b80fd9c3b7e6fc42b9450fa6dbc97d5b6eefd77b98a9c909183cfe05637ce2e7cef3d368d72d5abd06d2dbe690d8b203f527ee0885
7
+ data.tar.gz: 4b46fbd5003efb1421a0fdc5f99fe0511c0c89ed6ff7a9c8d08822d7cb03bd156cb82e526ea44c1608476f4ad4c5c9fc5ed1b1d918a2f8a4988e8b741c874b19
data/CHANGELOG.md CHANGED
@@ -5,17 +5,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
6
  ## [Unreleased][unreleased]
7
7
 
8
- ## [5.1.5] = 08-26-2015
8
+ ## [5.2.0] - 08-30-2015
9
9
 
10
- ### Fixed
11
- - Fixed errors when trying to call `#{association}_ids=` on an unpersisted node with UUIDs or an array thereof.
12
- - Removed extra Cypher query to replace relationships when working with unpersisted nodes and `association=`.
13
- - Bug related to Rails reloading an app and returning nodes without first reinitializing models, resulting in CypherNodes.
14
-
15
- ## [5.1.4] - 08-24-2015
10
+ ### Added
11
+ - `props_for_persistence`, `props_for_create`, `props_for_update` instance methods for all nodes and rels. Each returns a hash with properties appropriate for sending to the database in a Cypher query to create or update an object.
12
+ - Added `record_timestamps` configuration do default all `ActiveNode` and `ActiveRel` models to have `created_at` and `updated_at` timestamps (from #939, thanks @rebecca-eakins)
13
+ - Added `timestamp_type` configuration to specify how timestamps should be stored (from #939, thanks @rebecca-eakins)
16
14
 
17
- ### Fixed
18
- - `AssociationProxy` now responds to `serializable_hash` so that `include` can be used in `render json` in Rails controllers
15
+ ### Changed
16
+ - Methods related to basic node and rel persistence (`save`, `create_model`, `_create_node`, others) were refactored to make the processes simpler, clearer, and slightly faster.
17
+ - Unit test directory structure was rearranged to mirror the `lib` directory.
19
18
 
20
19
  ## [5.1.3] - 08-23-2015
21
20
 
@@ -23,6 +22,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
23
22
  - `has_one` associations are now properly cached (like `has_many` associations)
24
23
  - `QueryProxy` now responds to `#to_ary`. Fixes integration with ActiveModelSerializer gem
25
24
 
25
+
26
26
  ## [5.1.2] - 08-20-2015
27
27
 
28
28
  ### Fixed
@@ -79,10 +79,6 @@ module Neo4j::ActiveNode
79
79
  target.public_send(method_name, *args, &block)
80
80
  end
81
81
 
82
- def serializable_hash(options = {})
83
- to_a.map { |record| record.serializable_hash(options) }
84
- end
85
-
86
82
  private
87
83
 
88
84
  def target_for_missing_method(method_name)
@@ -3,7 +3,6 @@ module Neo4j
3
3
  # Provides a mapping between neo4j labels and Ruby classes
4
4
  module Labels
5
5
  extend ActiveSupport::Concern
6
- include Neo4j::ActiveNode::Labels::Reloading
7
6
 
8
7
  WRAPPED_CLASSES = []
9
8
  MODELS_FOR_LABELS_CACHE = {}
@@ -76,9 +75,17 @@ module Neo4j
76
75
  WRAPPED_CLASSES.clear
77
76
  end
78
77
 
78
+ protected
79
+
79
80
  module ClassMethods
80
81
  include Neo4j::ActiveNode::QueryMethods
81
82
 
83
+ def before_remove_const
84
+ associations.each_value(&:queue_model_refresh!)
85
+ MODELS_FOR_LABELS_CACHE.clear
86
+ WRAPPED_CLASSES.clear
87
+ end
88
+
82
89
  # Returns the object with the specified neo4j id.
83
90
  # @param [String,Integer] id of node to find
84
91
  def find(id)
@@ -23,7 +23,6 @@ module Neo4j::ActiveNode
23
23
  # There's a series of callbacks associated with save.
24
24
  # If any of the before_* callbacks return false the action is cancelled and save returns false.
25
25
  def save(*)
26
- update_magic_properties
27
26
  cascade_save do
28
27
  association_proxy_cache.clear
29
28
  create_or_update
@@ -47,25 +46,32 @@ module Neo4j::ActiveNode
47
46
  # Creates a model with values matching those of the instance attributes and returns its id.
48
47
  # @private
49
48
  # @return true
50
- def create_model(*)
51
- create_magic_properties
52
- set_timestamps
53
- create_magic_properties
54
- properties = self.class.declared_property_manager.convert_properties_to(self, :db, props)
55
- node = _create_node(properties)
49
+ def create_model
50
+ node = _create_node(props_for_create)
56
51
  init_on_load(node, node.props)
57
52
  send_props(@relationship_props) if @relationship_props
58
53
  @relationship_props = @deferred_nodes = nil
59
54
  true
60
55
  end
61
56
 
62
- def _create_node(*args)
63
- session = self.class.neo4j_session
64
- props = self.class.default_property_values(self)
65
- props.merge!(args[0]) if args[0].is_a?(Hash)
66
- set_classname(props)
67
- labels = self.class.mapped_label_names
68
- session.create_node(props, labels)
57
+ # TODO: This does not seem like it should be the responsibility of the node.
58
+ # Creates an unwrapped node in the database.
59
+ # @param [Hash] node_props The type-converted properties to be added to the new node.
60
+ # @param [Array] labels The labels to use for creating the new node.
61
+ # @return [Neo4j::Node] A CypherNode or EmbeddedNode
62
+ def _create_node(node_props, labels = labels_for_create)
63
+ self.class.neo4j_session.create_node(node_props, labels)
64
+ end
65
+
66
+ def inject_primary_key!(converted_props)
67
+ self.class.default_property_values(self).tap do |destination_props|
68
+ destination_props.merge!(converted_props) if converted_props.is_a?(Hash)
69
+ end
70
+ end
71
+
72
+ # @return [Array] Labels to be set on the node during a create event
73
+ def labels_for_create
74
+ self.class.mapped_label_names
69
75
  end
70
76
 
71
77
  private
@@ -164,7 +164,6 @@ module Neo4j
164
164
 
165
165
  # Deletes the relationships between all nodes for the last step in the QueryProxy chain. Executed in the database, callbacks will not be run.
166
166
  def delete_all_rels
167
- return unless start_object && start_object._persisted_obj
168
167
  self.query.delete(rel_var).exec
169
168
  end
170
169
 
@@ -40,10 +40,8 @@ module Neo4j
40
40
  end
41
41
 
42
42
  def save_and_associate_node(association_name, node, operator)
43
- if node.respond_to?(:changed?)
44
- node.save if node.changed? || !node.persisted?
45
- fail "Unable to defer node persistence, could not save #{node.inspect}" unless node.persisted?
46
- end
43
+ node.save if node.changed? || !node.persisted?
44
+ fail "Unable to defer node persistence, could not save #{node.inspect}" unless node.persisted?
47
45
  operator == :<< ? send(association_name).send(operator, node) : send(:"#{association_name}=", node)
48
46
  end
49
47
  end
@@ -55,6 +55,8 @@ module Neo4j
55
55
  end
56
56
 
57
57
  included do
58
+ include Neo4j::Timestamps if Neo4j::Config.record_timestamps
59
+
58
60
  def self.inherited(other)
59
61
  inherit_id_property(other)
60
62
  inherited_indexes(other) if self.respond_to?(:indexed_properties)
@@ -7,13 +7,7 @@ module Neo4j::ActiveRel
7
7
  class ModelClassInvalidError < RuntimeError; end
8
8
  class RelCreateFailedError < RuntimeError; end
9
9
 
10
- # Should probably find a way to not need this
11
- def association_proxy_cache
12
- {}
13
- end
14
-
15
10
  def save(*)
16
- update_magic_properties
17
11
  create_or_update
18
12
  end
19
13
 
@@ -21,12 +15,9 @@ module Neo4j::ActiveRel
21
15
  fail RelInvalidError, self unless save(*args)
22
16
  end
23
17
 
24
- def create_model(*)
18
+ def create_model
25
19
  validate_node_classes!
26
- create_magic_properties
27
- set_timestamps
28
- properties = self.class.declared_property_manager.convert_properties_to(self, :db, props)
29
- rel = _create_rel(from_node, to_node, properties)
20
+ rel = _create_rel(from_node, to_node, props_for_create)
30
21
  return self unless rel.respond_to?(:_persisted_obj)
31
22
  init_on_load(rel._persisted_obj, from_node, to_node, @rel_type)
32
23
  true
@@ -82,8 +73,6 @@ module Neo4j::ActiveRel
82
73
  end
83
74
 
84
75
  def _create_rel(from_node, to_node, props = {})
85
- set_classname(props, true)
86
-
87
76
  if from_node.id.nil? || to_node.id.nil?
88
77
  fail RelCreateFailedError, "Unable to create relationship (id is nil). from_node: #{from_node}, to_node: #{to_node}"
89
78
  end
@@ -44,6 +44,8 @@ module Neo4j
44
44
  end
45
45
 
46
46
  included do
47
+ include Neo4j::Timestamps if Neo4j::Config.record_timestamps
48
+
47
49
  def self.inherited(other)
48
50
  super
49
51
  end
data/lib/neo4j/config.rb CHANGED
@@ -2,19 +2,22 @@ module Neo4j
2
2
  # == Keeps configuration for neo4j
3
3
  #
4
4
  # == Configurations keys
5
- #
6
5
  class Config
7
6
  DEFAULT_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'neo4j', 'config.yml'))
8
7
  CLASS_NAME_PROPERTY_KEY = 'class_name_property'
9
8
 
10
9
  class << self
10
+ # In keeping with the Rails convention, this class writer lets you globally configure
11
+ # the incluse of timestamps on your nodes and rels. It defaults to false, requiring manual
12
+ # timestamp inclusion.
13
+ # @return [Boolean] the true/false value specified.
14
+ attr_writer :record_timestamps
11
15
  # @return [Fixnum] The location of the default configuration file.
12
16
  def default_file
13
17
  @default_file ||= DEFAULT_FILE
14
18
  end
15
19
 
16
20
  # Sets the location of the configuration YAML file and old deletes configurations.
17
- #
18
21
  # @param [String] file_path represent the path to the file.
19
22
  def default_file=(file_path)
20
23
  delete_all
@@ -93,6 +96,12 @@ module Neo4j
93
96
  configuration.to_yaml
94
97
  end
95
98
 
99
+ # @return [Boolean] The value of the config variable for including
100
+ # timestamps on all models.
101
+ def record_timestamps
102
+ @record_timestamps ||= false
103
+ end
104
+
96
105
  def class_name_property
97
106
  @_class_name_property = Neo4j::Config[CLASS_NAME_PROPERTY_KEY] || :_classname
98
107
  end
@@ -106,6 +115,11 @@ module Neo4j
106
115
  Neo4j::Config[:module_handling] || :none
107
116
  end
108
117
 
118
+ # @return [Class] The configured timestamps type (e.g. Integer) or the default DateTime.
119
+ def timestamp_type
120
+ Neo4j::Config[:timestamp_type] || DateTime
121
+ end
122
+
109
123
  def association_model_namespace
110
124
  Neo4j::Config[:association_model_namespace] || nil
111
125
  end
data/lib/neo4j/railtie.rb CHANGED
@@ -5,12 +5,6 @@ module Neo4j
5
5
  class Railtie < ::Rails::Railtie
6
6
  config.neo4j = ActiveSupport::OrderedOptions.new
7
7
 
8
- if const_defined?(:ActionDispatch)
9
- ActionDispatch::Reloader.to_prepare do
10
- Neo4j::ActiveNode::Labels::Reloading.reload_models!
11
- end
12
- end
13
-
14
8
  # Add ActiveModel translations to the I18n load_path
15
9
  initializer 'i18n' do
16
10
  config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
@@ -33,12 +33,16 @@ module Neo4j::Shared
33
33
 
34
34
  # Tweaks properties
35
35
  def register_magic_properties
36
- options[:type] ||= DateTime if name.to_sym == :created_at || name.to_sym == :updated_at
36
+ options[:type] ||= Neo4j::Config.timestamp_type if timestamp_prop?
37
37
 
38
38
  register_magic_typecaster
39
39
  register_type_converter
40
40
  end
41
41
 
42
+ def timestamp_prop?
43
+ name.to_sym == :created_at || name.to_sym == :updated_at
44
+ end
45
+
42
46
  def register_magic_typecaster
43
47
  found_typecaster = Neo4j::Shared::TypeConverters.typecaster_for(options[:type])
44
48
  return unless found_typecaster && found_typecaster.respond_to?(:primitive_type)
@@ -4,13 +4,38 @@ module Neo4j::Shared
4
4
 
5
5
  USES_CLASSNAME = []
6
6
 
7
+ # @return [Hash] Given a node's state, will call the appropriate `props_for_{action}` method.
8
+ def props_for_persistence
9
+ _persisted_obj ? props_for_update : props_for_create
10
+ end
11
+
7
12
  def update_model
8
13
  return if !changed_attributes || changed_attributes.empty?
14
+ _persisted_obj.update_props(props_for_update)
15
+ changed_attributes.clear
16
+ end
9
17
 
18
+ # Returns a hash containing:
19
+ # * All properties and values for insertion in the database
20
+ # * A `uuid` (or equivalent) key and value
21
+ # * A `_classname` property, if one is to be set
22
+ # * Timestamps, if the class is set to include them.
23
+ # Note that the UUID is added to the hash but is not set on the node.
24
+ # The timestamps, by comparison, are set on the node prior to addition in this hash.
25
+ # @return [Hash]
26
+ def props_for_create
27
+ inject_timestamps!
28
+ converted_props = props_for_db(props)
29
+ inject_classname!(converted_props)
30
+ return converted_props unless self.class.respond_to?(:default_property_values)
31
+ inject_primary_key!(converted_props)
32
+ end
33
+
34
+ # @return [Hash] Properties and values, type-converted and timestamped for the database.
35
+ def props_for_update
36
+ update_magic_properties
10
37
  changed_props = attributes.select { |k, _| changed_attributes.include?(k) }
11
- changed_props = self.class.declared_property_manager.convert_properties_to(self, :db, changed_props)
12
- _persisted_obj.update_props(changed_props)
13
- changed_attributes.clear
38
+ props_for_db(changed_props)
14
39
  end
15
40
 
16
41
  # Convenience method to set attribute and #save at the same time
@@ -115,7 +140,7 @@ module Neo4j::Shared
115
140
 
116
141
  def reload
117
142
  return self if new_record?
118
- association_proxy_cache.clear
143
+ association_proxy_cache.clear if respond_to?(:association_proxy_cache)
119
144
  changed_attributes && changed_attributes.clear
120
145
  unless reload_from_database
121
146
  @_deleted = true
@@ -159,11 +184,12 @@ module Neo4j::Shared
159
184
 
160
185
  private
161
186
 
162
- def model_cache_key
163
- self.class.model_name.cache_key
187
+ def props_for_db(props_hash)
188
+ self.class.declared_property_manager.convert_properties_to(self, :db, props_hash)
164
189
  end
165
190
 
166
- def create_magic_properties
191
+ def model_cache_key
192
+ self.class.model_name.cache_key
167
193
  end
168
194
 
169
195
  def update_magic_properties
@@ -171,16 +197,28 @@ module Neo4j::Shared
171
197
  end
172
198
 
173
199
  # Inserts the _classname property into an object's properties during object creation.
174
- def set_classname(props, check_version = true)
200
+ def inject_classname!(props, check_version = true)
175
201
  props[:_classname] = self.class.name if self.class.cached_class?(check_version)
176
202
  end
177
203
 
178
- def set_timestamps
204
+ def set_classname(props, check_version = true)
205
+ warning = 'This method has been replaced with `inject_classname!` and will be removed in a future version'.freeze
206
+ ActiveSupport::Deprecation.warn warning, caller
207
+ inject_classname!(props, check_version)
208
+ end
209
+
210
+ def inject_timestamps!
179
211
  now = DateTime.now
180
212
  self.created_at ||= now if respond_to?(:created_at=)
181
213
  self.updated_at ||= now if respond_to?(:updated_at=)
182
214
  end
183
215
 
216
+ def set_timestamps
217
+ warning = 'This method has been replaced with `inject_timestamps!` and will be removed in a future version'.freeze
218
+ ActiveSupport::Deprecation.warn warning, caller
219
+ inject_timestamps!
220
+ end
221
+
184
222
  module ClassMethods
185
223
  # Determines whether a model should insert a _classname property. This can be used to override the automatic matching of returned
186
224
  # objects to models.
@@ -3,9 +3,7 @@ module Neo4j
3
3
  # This mixin includes a created_at timestamp property
4
4
  module Created
5
5
  extend ActiveSupport::Concern
6
- included do
7
- property :created_at, type: DateTime
8
- end
6
+ included { property :created_at }
9
7
  end
10
8
  end
11
9
  end
@@ -3,9 +3,7 @@ module Neo4j
3
3
  # This mixin includes a updated_at timestamp property
4
4
  module Updated
5
5
  extend ActiveSupport::Concern
6
- included do
7
- property :updated_at, type: DateTime
8
- end
6
+ included { property :updated_at }
9
7
  end
10
8
  end
11
9
  end
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = '5.1.5'
2
+ VERSION = '5.2.0'
3
3
  end
data/lib/neo4j.rb CHANGED
@@ -60,7 +60,6 @@ require 'neo4j/active_node/query/query_proxy_enumerable'
60
60
  require 'neo4j/active_node/query/query_proxy_find_in_batches'
61
61
  require 'neo4j/active_node/query/query_proxy_eager_loading'
62
62
  require 'neo4j/active_node/query/query_proxy_link'
63
- require 'neo4j/active_node/labels/reloading'
64
63
  require 'neo4j/active_node/labels'
65
64
  require 'neo4j/active_node/id_property/accessor'
66
65
  require 'neo4j/active_node/id_property'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.5
4
+ version: 5.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Ronge, Brian Underwood, Chris Grigg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-27 00:00:00.000000000 Z
11
+ date: 2015-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: orm_adapter
@@ -236,7 +236,6 @@ files:
236
236
  - lib/neo4j/active_node/id_property/accessor.rb
237
237
  - lib/neo4j/active_node/initialize.rb
238
238
  - lib/neo4j/active_node/labels.rb
239
- - lib/neo4j/active_node/labels/reloading.rb
240
239
  - lib/neo4j/active_node/node_wrapper.rb
241
240
  - lib/neo4j/active_node/orm_adapter.rb
242
241
  - lib/neo4j/active_node/persistence.rb
@@ -323,7 +322,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
323
322
  version: '0'
324
323
  requirements: []
325
324
  rubyforge_project: neo4j
326
- rubygems_version: 2.4.6
325
+ rubygems_version: 2.4.5
327
326
  signing_key:
328
327
  specification_version: 4
329
328
  summary: A graph database for Ruby
@@ -1,21 +0,0 @@
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