neo4j 3.0.0.rc.3 → 3.0.0.rc.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +10 -0
- data/Gemfile +5 -4
- data/README.md +1 -1
- data/config/neo4j/add_classnames.yml +1 -0
- data/lib/neo4j.rb +2 -0
- data/lib/neo4j/active_node.rb +4 -1
- data/lib/neo4j/active_node/has_n.rb +75 -9
- data/lib/neo4j/active_node/has_n/association.rb +5 -4
- data/lib/neo4j/active_node/id_property.rb +50 -5
- data/lib/neo4j/active_node/initialize.rb +1 -0
- data/lib/neo4j/active_node/labels.rb +15 -3
- data/lib/neo4j/active_node/orm_adapter.rb +1 -1
- data/lib/neo4j/active_node/persistence.rb +39 -0
- data/lib/neo4j/active_node/query/query_proxy.rb +29 -6
- data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +20 -0
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +24 -12
- data/lib/neo4j/active_node/query_methods.rb +21 -10
- data/lib/neo4j/active_node/reflection.rb +85 -0
- data/lib/neo4j/active_rel/callbacks.rb +3 -1
- data/lib/neo4j/active_rel/initialize.rb +2 -2
- data/lib/neo4j/active_rel/persistence.rb +23 -14
- data/lib/neo4j/active_rel/property.rb +9 -10
- data/lib/neo4j/active_rel/query.rb +51 -29
- data/lib/neo4j/active_rel/related_node.rb +2 -6
- data/lib/neo4j/migration.rb +185 -0
- data/lib/neo4j/paginated.rb +2 -1
- data/lib/neo4j/railtie.rb +13 -8
- data/lib/neo4j/shared/persistence.rb +10 -56
- data/lib/neo4j/shared/property.rb +15 -6
- data/lib/neo4j/tasks/migration.rake +23 -0
- data/lib/neo4j/version.rb +1 -1
- metadata +7 -2
@@ -3,7 +3,6 @@ module Neo4j::ActiveRel
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
include Enumerable
|
7
6
|
|
8
7
|
# Returns the object with the specified neo4j id.
|
9
8
|
# @param [String,Fixnum] id of node to find
|
@@ -13,54 +12,77 @@ module Neo4j::ActiveRel
|
|
13
12
|
find_by_id(id, session)
|
14
13
|
end
|
15
14
|
|
15
|
+
# Loads the relationship using its neo_id.
|
16
16
|
def find_by_id(key, session = Neo4j::Session.current!)
|
17
17
|
Neo4j::Relationship.load(key.to_i, session)
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Performs a very basic match on the relationship.
|
21
|
+
# This is not executed lazily, it will immediately return matching objects.
|
22
|
+
# To use a string, prefix the property with "r1"
|
23
|
+
# @example Match with a string
|
24
|
+
# MyRelClass.where('r1.grade > r1')
|
21
25
|
def where(args={})
|
22
|
-
|
23
|
-
Neo4j::Session.query("MATCH n1-[r1:`#{self._type}`]->(#{cypher_node_string(:inbound)}) WHERE #{where_string(args)} RETURN r1")
|
24
|
-
else
|
25
|
-
self._from_class.query_as(:n1).match("(#{cypher_node_string(:outbound)})-[r1:`#{self._type}`]->(#{cypher_node_string(:inbound)})").where(Hash["r1" => args])
|
26
|
-
end
|
27
|
-
return self
|
26
|
+
Neo4j::Session.query.match("#{cypher_string(:outbound)}-[r1:`#{self._type}`]->#{cypher_string(:inbound)}").where(where_string(args)).pluck(:r1)
|
28
27
|
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@query.pluck(:r1)
|
35
|
-
end.each {|r| yield r }
|
29
|
+
# Performs a basic match on the relationship, returning all results.
|
30
|
+
# This is not executed lazily, it will immediately return matching objects.
|
31
|
+
def all
|
32
|
+
all_query.pluck(:r1)
|
36
33
|
end
|
37
34
|
|
38
35
|
def first
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
all_query.limit(1).order("ID(r1)").pluck(:r1).first
|
37
|
+
end
|
38
|
+
|
39
|
+
def last
|
40
|
+
all_query.limit(1).order("ID(r1) DESC").pluck(:r1).first
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def all_query
|
46
|
+
Neo4j::Session.query.match("#{cypher_string}-[r1:`#{self._type}`]->#{cypher_string(:inbound)}")
|
44
47
|
end
|
45
48
|
|
46
|
-
def
|
49
|
+
def cypher_string(dir = :outbound)
|
47
50
|
case dir
|
48
51
|
when :outbound
|
49
|
-
|
52
|
+
identifier = '(n1'
|
53
|
+
identifier + (_from_class == :any ? ')' : cypher_label(:outbound))
|
50
54
|
when :inbound
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
identifier = '(n2'
|
56
|
+
identifier + (_to_class == :any ? ')' : cypher_label(:inbound))
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
|
-
|
60
|
+
def cypher_label(dir = :outbound)
|
61
|
+
target_class = dir == :outbound ? as_constant(_from_class) : as_constant(_to_class)
|
62
|
+
":`#{target_class.mapped_label_name}`)"
|
63
|
+
end
|
64
|
+
|
65
|
+
def as_constant(given_class)
|
66
|
+
case
|
67
|
+
when given_class.is_a?(String)
|
68
|
+
given_class.constantize
|
69
|
+
when given_class.is_a?(Symbol)
|
70
|
+
given_class.to_s.constantize
|
71
|
+
else
|
72
|
+
given_class
|
73
|
+
end
|
74
|
+
end
|
57
75
|
|
58
76
|
def where_string(args)
|
59
|
-
args.
|
60
|
-
|
61
|
-
|
77
|
+
if args.is_a?(Hash)
|
78
|
+
args.map do |k, v|
|
79
|
+
v.is_a?(Integer) ? "r1.#{k} = #{v}" : "r1.#{k} = '#{v}'"
|
80
|
+
end.join(', ')
|
81
|
+
else
|
82
|
+
args
|
83
|
+
end
|
62
84
|
end
|
63
85
|
|
64
86
|
end
|
65
87
|
end
|
66
|
-
end
|
88
|
+
end
|
@@ -2,14 +2,10 @@ module Neo4j::ActiveRel
|
|
2
2
|
# A container for ActiveRel's :inbound and :outbound methods. It provides lazy loading of nodes.
|
3
3
|
class RelatedNode
|
4
4
|
|
5
|
-
class InvalidParameterError < StandardError
|
6
|
-
def message
|
7
|
-
'RelatedNode must be initialized with either a node ID or node'
|
8
|
-
end
|
9
|
-
end
|
5
|
+
class InvalidParameterError < StandardError; end
|
10
6
|
|
11
7
|
def initialize(node = nil)
|
12
|
-
@node = valid_node_param?(node) ? node : (raise InvalidParameterError
|
8
|
+
@node = valid_node_param?(node) ? node : (raise InvalidParameterError, 'RelatedNode must be initialized with either a node ID or node' )
|
13
9
|
end
|
14
10
|
|
15
11
|
def == (obj)
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module Neo4j
|
2
|
+
class Migration
|
3
|
+
class AddIdProperty < Neo4j::Migration
|
4
|
+
attr_reader :models_filename
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@models_filename = File.join(Rails.root.join('db', 'neo4j-migrate'), 'add_id_property.yml')
|
8
|
+
end
|
9
|
+
|
10
|
+
def migrate
|
11
|
+
models = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(models_filename))[:models]
|
12
|
+
puts "This task will add an ID Property every node in the given file."
|
13
|
+
puts "It may take a significant amount of time, please be patient."
|
14
|
+
models.each do |model|
|
15
|
+
puts
|
16
|
+
puts
|
17
|
+
puts "Adding IDs to #{model}"
|
18
|
+
add_ids_to model.constantize
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def setup
|
23
|
+
FileUtils.mkdir_p("db/neo4j-migrate")
|
24
|
+
unless File.file?(models_filename)
|
25
|
+
File.open(models_filename, 'w') do |file|
|
26
|
+
file.write("# Provide models to which IDs should be added.\n# It will only modify nodes that do not have IDs. There is no danger of overwriting data.\n# models: [Student,Lesson,Teacher,Exam]\nmodels: []")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def add_ids_to(model)
|
34
|
+
require 'benchmark'
|
35
|
+
|
36
|
+
max_per_batch = (ENV['MAX_PER_BATCH'] || default_max_per_batch).to_i
|
37
|
+
|
38
|
+
label = model.mapped_label_name
|
39
|
+
property = model.primary_key
|
40
|
+
nodes_left = 1
|
41
|
+
last_time_taken = nil
|
42
|
+
|
43
|
+
until nodes_left == 0
|
44
|
+
nodes_left = Neo4j::Session.query.match(n: label).where("NOT has(n.#{property})").return("COUNT(n) AS ids").first.ids
|
45
|
+
|
46
|
+
time_per_node = last_time_taken / max_per_batch if last_time_taken
|
47
|
+
print "Running first batch...\r"
|
48
|
+
if time_per_node
|
49
|
+
eta_seconds = (nodes_left * time_per_node).round
|
50
|
+
print "#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)\r"
|
51
|
+
end
|
52
|
+
|
53
|
+
return if nodes_left == 0
|
54
|
+
to_set = [nodes_left, max_per_batch].min
|
55
|
+
|
56
|
+
new_ids = to_set.times.map { new_id_for(model) }
|
57
|
+
begin
|
58
|
+
last_time_taken = id_batch_set(label, property, new_ids, to_set)
|
59
|
+
rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
|
60
|
+
new_max_per_batch = (max_per_batch * 0.8).round
|
61
|
+
puts "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
|
62
|
+
max_per_batch = new_max_per_batch
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def id_batch_set(label, property, new_ids, to_set)
|
68
|
+
Benchmark.realtime do
|
69
|
+
Neo4j::Transaction.run do
|
70
|
+
Neo4j::Session.query("MATCH (n:`#{label}`) WHERE NOT has(n.#{property})
|
71
|
+
with COLLECT(n) as nodes, #{new_ids} as ids
|
72
|
+
FOREACH(i in range(0,#{to_set - 1})|
|
73
|
+
FOREACH(node in [nodes[i]]|
|
74
|
+
SET node.#{property} = ids[i]))
|
75
|
+
RETURN distinct(true)
|
76
|
+
LIMIT #{to_set}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def default_max_per_batch
|
82
|
+
900
|
83
|
+
end
|
84
|
+
|
85
|
+
def new_id_for(model)
|
86
|
+
if model.id_property_info[:type][:auto]
|
87
|
+
SecureRandom::uuid
|
88
|
+
else
|
89
|
+
model.new.send(model.id_property_info[:type][:on])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class AddClassnames < Neo4j::Migration
|
95
|
+
attr_reader :classnames_filename, :classnames_filepath
|
96
|
+
|
97
|
+
def initialize
|
98
|
+
@classnames_filename = 'add_classnames.yml'
|
99
|
+
@classnames_filepath = File.join(Rails.root.join('db', 'neo4j-migrate'), classnames_filename)
|
100
|
+
end
|
101
|
+
|
102
|
+
def migrate
|
103
|
+
puts "Adding classnames. This make take some time."
|
104
|
+
execute(true)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test
|
108
|
+
puts "TESTING! No queries will be executed."
|
109
|
+
execute(false)
|
110
|
+
end
|
111
|
+
|
112
|
+
def setup
|
113
|
+
puts "Creating file #{classnames_filepath}. Please use this as the migration guide."
|
114
|
+
FileUtils.mkdir_p("db/neo4j-migrate")
|
115
|
+
unless File.file?(@classnames_filepath)
|
116
|
+
source = File.join(File.dirname(__FILE__), "..", "..", "config", "neo4j", classnames_filename)
|
117
|
+
FileUtils.copy_file(source, classnames_filepath)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def execute(migrate = false)
|
124
|
+
file_init
|
125
|
+
map = []
|
126
|
+
map.push :nodes if @model_map[:nodes]
|
127
|
+
map.push :relationships if @model_map[:relationships]
|
128
|
+
map.each do |type|
|
129
|
+
@model_map[type].each do |action, labels|
|
130
|
+
do_classnames(action, labels, type, migrate)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def do_classnames(action, labels, type, migrate = false)
|
136
|
+
method = type == :nodes ? :node_cypher : :rel_cypher
|
137
|
+
labels.each do |label|
|
138
|
+
puts cypher = self.send(method, label, action)
|
139
|
+
execute_cypher(cypher) if migrate
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def file_init
|
144
|
+
@model_map = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(classnames_filepath))
|
145
|
+
end
|
146
|
+
|
147
|
+
def node_cypher(label, action)
|
148
|
+
where, phrase_start = action_variables(action, 'n')
|
149
|
+
puts "#{phrase_start} _classname '#{label}' on nodes with matching label:"
|
150
|
+
"MATCH (n:`#{label}`) #{where} SET n._classname = '#{label}' RETURN COUNT(n) as modified"
|
151
|
+
end
|
152
|
+
|
153
|
+
def rel_cypher(hash, action)
|
154
|
+
label = hash[0]
|
155
|
+
value = hash[1]
|
156
|
+
from = value[:from]
|
157
|
+
raise "All relationships require a 'type'" unless value[:type]
|
158
|
+
|
159
|
+
from_cypher = from ? "(from:`#{from}`)" : "(from)"
|
160
|
+
to = value[:to]
|
161
|
+
to_cypher = to ? "(to:`#{to}`)" : "(to)"
|
162
|
+
type = "[r:`#{value[:type]}`]"
|
163
|
+
where, phrase_start = action_variables(action, 'r')
|
164
|
+
puts "#{phrase_start} _classname '#{label}' where type is '#{value[:type]}' using cypher:"
|
165
|
+
"MATCH #{from_cypher}-#{type}->#{to_cypher} #{where} SET r._classname = '#{label}' return COUNT(r) as modified"
|
166
|
+
end
|
167
|
+
|
168
|
+
def execute_cypher(query_string)
|
169
|
+
puts "Modified #{Neo4j::Session.query(query_string).first.modified} records"
|
170
|
+
puts ""
|
171
|
+
end
|
172
|
+
|
173
|
+
def action_variables(action, identifier)
|
174
|
+
case action
|
175
|
+
when 'overwrite'
|
176
|
+
['', 'Overwriting']
|
177
|
+
when 'add'
|
178
|
+
["WHERE NOT HAS(#{identifier}._classname)", 'Adding']
|
179
|
+
else
|
180
|
+
raise "Invalid action #{action} specified"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/lib/neo4j/paginated.rb
CHANGED
@@ -10,10 +10,11 @@ module Neo4j
|
|
10
10
|
def self.create_from(source, page, per_page)
|
11
11
|
#partial = source.drop((page-1) * per_page).first(per_page)
|
12
12
|
partial = source.skip(page-1).limit(per_page)
|
13
|
-
Paginated.new(partial, source.
|
13
|
+
Paginated.new(partial, source.count, page)
|
14
14
|
end
|
15
15
|
|
16
16
|
delegate :each, :to => :items
|
17
|
+
delegate :pluck, :to => :items
|
17
18
|
delegate :size, :[], :to => :items
|
18
19
|
end
|
19
20
|
end
|
data/lib/neo4j/railtie.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'active_support/notifications'
|
2
|
+
require 'rails/railtie'
|
2
3
|
|
3
4
|
module Neo4j
|
4
|
-
|
5
|
+
class Railtie < ::Rails::Railtie
|
5
6
|
config.neo4j = ActiveSupport::OrderedOptions.new
|
6
7
|
|
7
8
|
# Add ActiveModel translations to the I18n load_path
|
@@ -9,6 +10,11 @@ module Neo4j
|
|
9
10
|
config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
|
10
11
|
end
|
11
12
|
|
13
|
+
rake_tasks do
|
14
|
+
load 'neo4j/tasks/neo4j_server.rake'
|
15
|
+
load 'neo4j/tasks/migration.rake'
|
16
|
+
end
|
17
|
+
|
12
18
|
class << self
|
13
19
|
def java_platform?
|
14
20
|
RUBY_PLATFORM =~ /java/
|
@@ -26,7 +32,7 @@ module Neo4j
|
|
26
32
|
end
|
27
33
|
|
28
34
|
if cfg.sessions.empty?
|
29
|
-
cfg.sessions << {type: cfg.session_type, path: cfg.session_path, options: cfg.session_options}
|
35
|
+
cfg.sessions << { type: cfg.session_type, path: cfg.session_path, options: cfg.session_options }
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
@@ -45,18 +51,17 @@ module Neo4j
|
|
45
51
|
raise "Tried to start embedded Neo4j db without using JRuby (got #{RUBY_PLATFORM}), please run `rvm jruby`"
|
46
52
|
end
|
47
53
|
|
48
|
-
if
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
session = if session_opts.key?(:name)
|
55
|
+
Neo4j::Session.open_named(session_opts[:type], session_opts[:name], session_opts[:default], session_opts[:path])
|
56
|
+
else
|
57
|
+
Neo4j::Session.open(session_opts[:type], session_opts[:path], session_opts[:options])
|
58
|
+
end
|
53
59
|
|
54
60
|
start_embedded_session(session) if session_opts[:type] == :embedded_db
|
55
61
|
end
|
56
62
|
|
57
63
|
end
|
58
64
|
|
59
|
-
|
60
65
|
# Starting Neo after :load_config_initializers allows apps to
|
61
66
|
# register migrations in config/initializers
|
62
67
|
initializer "neo4j.start", :after => :load_config_initializers do |app|
|
@@ -1,45 +1,9 @@
|
|
1
1
|
module Neo4j::Shared
|
2
2
|
module Persistence
|
3
3
|
|
4
|
-
class RecordInvalidError < RuntimeError
|
5
|
-
attr_reader :record
|
6
|
-
|
7
|
-
def initialize(record)
|
8
|
-
@record = record
|
9
|
-
super(@record.errors.full_messages.join(", "))
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
4
|
extend ActiveSupport::Concern
|
14
5
|
include Neo4j::TypeConverters
|
15
6
|
|
16
|
-
# Saves the model.
|
17
|
-
#
|
18
|
-
# If the model is new a record gets created in the database, otherwise the existing record gets updated.
|
19
|
-
# If perform_validation is true validations run.
|
20
|
-
# If any of them fail the action is cancelled and save returns false. If the flag is false validations are bypassed altogether. See ActiveRecord::Validations for more information.
|
21
|
-
# There’s a series of callbacks associated with save. If any of the before_* callbacks return false the action is cancelled and save returns false.
|
22
|
-
def save(*)
|
23
|
-
update_magic_properties
|
24
|
-
create_or_update
|
25
|
-
end
|
26
|
-
|
27
|
-
# Persist the object to the database. Validations and Callbacks are included
|
28
|
-
# by default but validation can be disabled by passing :validate => false
|
29
|
-
# to #save! Creates a new transaction.
|
30
|
-
#
|
31
|
-
# @raise a RecordInvalidError if there is a problem during save.
|
32
|
-
# @param (see Neo4j::Rails::Validations#save)
|
33
|
-
# @return nil
|
34
|
-
# @see #save
|
35
|
-
# @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
|
36
|
-
# @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
|
37
|
-
def save!(*args)
|
38
|
-
unless save(*args)
|
39
|
-
raise RecordInvalidError.new(self)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
7
|
def update_model
|
44
8
|
if changed_attributes && !changed_attributes.empty?
|
45
9
|
changed_props = attributes.select{|k,v| changed_attributes.include?(k)}
|
@@ -49,7 +13,6 @@ module Neo4j::Shared
|
|
49
13
|
end
|
50
14
|
end
|
51
15
|
|
52
|
-
|
53
16
|
# Convenience method to set attribute and #save at the same time
|
54
17
|
# @param [Symbol, String] attribute of the attribute to update
|
55
18
|
# @param [Object] value to set
|
@@ -66,13 +29,6 @@ module Neo4j::Shared
|
|
66
29
|
self.save!
|
67
30
|
end
|
68
31
|
|
69
|
-
# Convenience method to set multiple attributes and #save at the same time
|
70
|
-
# @param [Hash] attributes of names and values of attributes to set
|
71
|
-
def update_attributes(attributes)
|
72
|
-
assign_attributes(attributes)
|
73
|
-
self.save
|
74
|
-
end
|
75
|
-
|
76
32
|
def create_or_update
|
77
33
|
# since the same model can be created or updated twice from a relationship we have to have this guard
|
78
34
|
@_create_or_updating = true
|
@@ -145,6 +101,7 @@ module Neo4j::Shared
|
|
145
101
|
|
146
102
|
def reload
|
147
103
|
return self if new_record?
|
104
|
+
clear_association_cache
|
148
105
|
changed_attributes && changed_attributes.clear
|
149
106
|
unless reload_from_database
|
150
107
|
@_deleted = true
|
@@ -164,30 +121,34 @@ module Neo4j::Shared
|
|
164
121
|
# Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
|
165
122
|
# If saving fails because the resource is invalid then false will be returned.
|
166
123
|
def update(attributes)
|
167
|
-
self.attributes = attributes
|
124
|
+
self.attributes = process_attributes(attributes)
|
168
125
|
save
|
169
126
|
end
|
170
127
|
alias_method :update_attributes, :update
|
171
128
|
|
172
129
|
# Same as {#update_attributes}, but raises an exception if saving fails.
|
173
130
|
def update!(attributes)
|
174
|
-
self.attributes = attributes
|
131
|
+
self.attributes = process_attributes(attributes)
|
175
132
|
save!
|
176
133
|
end
|
177
134
|
alias_method :update_attributes!, :update!
|
178
135
|
|
179
136
|
def cache_key
|
180
137
|
if self.new_record?
|
181
|
-
"#{
|
138
|
+
"#{model_cache_key}/new"
|
182
139
|
elsif self.respond_to?(:updated_at) && !self.updated_at.blank?
|
183
|
-
"#{
|
140
|
+
"#{model_cache_key}/#{neo_id}-#{self.updated_at.utc.to_s(:number)}"
|
184
141
|
else
|
185
|
-
"#{
|
142
|
+
"#{model_cache_key}/#{neo_id}"
|
186
143
|
end
|
187
144
|
end
|
188
145
|
|
189
146
|
private
|
190
147
|
|
148
|
+
def model_cache_key
|
149
|
+
self.class.model_name.cache_key
|
150
|
+
end
|
151
|
+
|
191
152
|
def create_magic_properties
|
192
153
|
end
|
193
154
|
|
@@ -199,16 +160,9 @@ module Neo4j::Shared
|
|
199
160
|
props[:_classname] = self.class.name if self.class.cached_class?
|
200
161
|
end
|
201
162
|
|
202
|
-
# def assign_attributes(attributes)
|
203
|
-
# attributes.each do |attribute, value|
|
204
|
-
# send("#{attribute}=", value)
|
205
|
-
# end
|
206
|
-
# end
|
207
|
-
|
208
163
|
def set_timestamps
|
209
164
|
self.created_at = DateTime.now if respond_to?(:created_at=)
|
210
165
|
self.updated_at = self.created_at if respond_to?(:updated_at=)
|
211
166
|
end
|
212
|
-
|
213
167
|
end
|
214
168
|
end
|