activegraph 11.0.0.beta.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2016 -0
  3. data/CONTRIBUTORS +12 -0
  4. data/Gemfile +24 -0
  5. data/README.md +111 -0
  6. data/activegraph.gemspec +52 -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_graph.rb +123 -0
  12. data/lib/active_graph/ansi.rb +14 -0
  13. data/lib/active_graph/attribute_set.rb +32 -0
  14. data/lib/active_graph/base.rb +77 -0
  15. data/lib/active_graph/class_arguments.rb +39 -0
  16. data/lib/active_graph/config.rb +135 -0
  17. data/lib/active_graph/core.rb +14 -0
  18. data/lib/active_graph/core/connection_failed_error.rb +6 -0
  19. data/lib/active_graph/core/cypher_error.rb +37 -0
  20. data/lib/active_graph/core/entity.rb +11 -0
  21. data/lib/active_graph/core/instrumentable.rb +37 -0
  22. data/lib/active_graph/core/label.rb +135 -0
  23. data/lib/active_graph/core/logging.rb +44 -0
  24. data/lib/active_graph/core/node.rb +15 -0
  25. data/lib/active_graph/core/querable.rb +41 -0
  26. data/lib/active_graph/core/query.rb +485 -0
  27. data/lib/active_graph/core/query_builder.rb +18 -0
  28. data/lib/active_graph/core/query_clauses.rb +727 -0
  29. data/lib/active_graph/core/query_ext.rb +24 -0
  30. data/lib/active_graph/core/query_find_in_batches.rb +46 -0
  31. data/lib/active_graph/core/record.rb +51 -0
  32. data/lib/active_graph/core/result.rb +31 -0
  33. data/lib/active_graph/core/schema.rb +65 -0
  34. data/lib/active_graph/core/schema_errors.rb +12 -0
  35. data/lib/active_graph/core/wrappable.rb +30 -0
  36. data/lib/active_graph/errors.rb +59 -0
  37. data/lib/active_graph/lazy_attribute_hash.rb +38 -0
  38. data/lib/active_graph/migration.rb +148 -0
  39. data/lib/active_graph/migrations.rb +27 -0
  40. data/lib/active_graph/migrations/base.rb +77 -0
  41. data/lib/active_graph/migrations/check_pending.rb +20 -0
  42. data/lib/active_graph/migrations/helpers.rb +105 -0
  43. data/lib/active_graph/migrations/helpers/id_property.rb +72 -0
  44. data/lib/active_graph/migrations/helpers/relationships.rb +66 -0
  45. data/lib/active_graph/migrations/helpers/schema.rb +63 -0
  46. data/lib/active_graph/migrations/migration_file.rb +24 -0
  47. data/lib/active_graph/migrations/runner.rb +195 -0
  48. data/lib/active_graph/migrations/schema.rb +64 -0
  49. data/lib/active_graph/migrations/schema_migration.rb +14 -0
  50. data/lib/active_graph/model_schema.rb +139 -0
  51. data/lib/active_graph/node.rb +110 -0
  52. data/lib/active_graph/node/callbacks.rb +8 -0
  53. data/lib/active_graph/node/dependent.rb +11 -0
  54. data/lib/active_graph/node/dependent/association_methods.rb +49 -0
  55. data/lib/active_graph/node/dependent/query_proxy_methods.rb +52 -0
  56. data/lib/active_graph/node/dependent_callbacks.rb +31 -0
  57. data/lib/active_graph/node/enum.rb +26 -0
  58. data/lib/active_graph/node/has_n.rb +602 -0
  59. data/lib/active_graph/node/has_n/association.rb +278 -0
  60. data/lib/active_graph/node/has_n/association/rel_factory.rb +61 -0
  61. data/lib/active_graph/node/has_n/association/rel_wrapper.rb +23 -0
  62. data/lib/active_graph/node/has_n/association_cypher_methods.rb +108 -0
  63. data/lib/active_graph/node/id_property.rb +224 -0
  64. data/lib/active_graph/node/id_property/accessor.rb +62 -0
  65. data/lib/active_graph/node/initialize.rb +21 -0
  66. data/lib/active_graph/node/labels.rb +207 -0
  67. data/lib/active_graph/node/labels/index.rb +37 -0
  68. data/lib/active_graph/node/labels/reloading.rb +21 -0
  69. data/lib/active_graph/node/node_list_formatter.rb +13 -0
  70. data/lib/active_graph/node/node_wrapper.rb +54 -0
  71. data/lib/active_graph/node/orm_adapter.rb +82 -0
  72. data/lib/active_graph/node/persistence.rb +186 -0
  73. data/lib/active_graph/node/property.rb +60 -0
  74. data/lib/active_graph/node/query.rb +76 -0
  75. data/lib/active_graph/node/query/query_proxy.rb +367 -0
  76. data/lib/active_graph/node/query/query_proxy_eager_loading.rb +177 -0
  77. data/lib/active_graph/node/query/query_proxy_eager_loading/association_tree.rb +75 -0
  78. data/lib/active_graph/node/query/query_proxy_enumerable.rb +110 -0
  79. data/lib/active_graph/node/query/query_proxy_find_in_batches.rb +19 -0
  80. data/lib/active_graph/node/query/query_proxy_link.rb +139 -0
  81. data/lib/active_graph/node/query/query_proxy_methods.rb +303 -0
  82. data/lib/active_graph/node/query/query_proxy_methods_of_mass_updating.rb +99 -0
  83. data/lib/active_graph/node/query_methods.rb +68 -0
  84. data/lib/active_graph/node/reflection.rb +86 -0
  85. data/lib/active_graph/node/rels.rb +11 -0
  86. data/lib/active_graph/node/scope.rb +166 -0
  87. data/lib/active_graph/node/unpersisted.rb +48 -0
  88. data/lib/active_graph/node/validations.rb +59 -0
  89. data/lib/active_graph/paginated.rb +27 -0
  90. data/lib/active_graph/railtie.rb +108 -0
  91. data/lib/active_graph/relationship.rb +68 -0
  92. data/lib/active_graph/relationship/callbacks.rb +21 -0
  93. data/lib/active_graph/relationship/initialize.rb +28 -0
  94. data/lib/active_graph/relationship/persistence.rb +133 -0
  95. data/lib/active_graph/relationship/persistence/query_factory.rb +95 -0
  96. data/lib/active_graph/relationship/property.rb +92 -0
  97. data/lib/active_graph/relationship/query.rb +99 -0
  98. data/lib/active_graph/relationship/rel_wrapper.rb +31 -0
  99. data/lib/active_graph/relationship/related_node.rb +87 -0
  100. data/lib/active_graph/relationship/types.rb +80 -0
  101. data/lib/active_graph/relationship/validations.rb +8 -0
  102. data/lib/active_graph/schema/operation.rb +102 -0
  103. data/lib/active_graph/shared.rb +48 -0
  104. data/lib/active_graph/shared/attributes.rb +217 -0
  105. data/lib/active_graph/shared/callbacks.rb +66 -0
  106. data/lib/active_graph/shared/cypher.rb +37 -0
  107. data/lib/active_graph/shared/declared_properties.rb +204 -0
  108. data/lib/active_graph/shared/declared_property.rb +109 -0
  109. data/lib/active_graph/shared/declared_property/index.rb +37 -0
  110. data/lib/active_graph/shared/enum.rb +167 -0
  111. data/lib/active_graph/shared/filtered_hash.rb +79 -0
  112. data/lib/active_graph/shared/identity.rb +34 -0
  113. data/lib/active_graph/shared/initialize.rb +65 -0
  114. data/lib/active_graph/shared/marshal.rb +23 -0
  115. data/lib/active_graph/shared/mass_assignment.rb +63 -0
  116. data/lib/active_graph/shared/permitted_attributes.rb +28 -0
  117. data/lib/active_graph/shared/persistence.rb +272 -0
  118. data/lib/active_graph/shared/property.rb +249 -0
  119. data/lib/active_graph/shared/query_factory.rb +122 -0
  120. data/lib/active_graph/shared/rel_type_converters.rb +43 -0
  121. data/lib/active_graph/shared/serialized_properties.rb +30 -0
  122. data/lib/active_graph/shared/type_converters.rb +439 -0
  123. data/lib/active_graph/shared/typecasted_attributes.rb +99 -0
  124. data/lib/active_graph/shared/typecaster.rb +53 -0
  125. data/lib/active_graph/shared/validations.rb +44 -0
  126. data/lib/active_graph/tasks/migration.rake +204 -0
  127. data/lib/active_graph/timestamps.rb +11 -0
  128. data/lib/active_graph/timestamps/created.rb +9 -0
  129. data/lib/active_graph/timestamps/updated.rb +9 -0
  130. data/lib/active_graph/transaction.rb +22 -0
  131. data/lib/active_graph/transactions.rb +57 -0
  132. data/lib/active_graph/type_converters.rb +7 -0
  133. data/lib/active_graph/undeclared_properties.rb +53 -0
  134. data/lib/active_graph/version.rb +3 -0
  135. data/lib/active_graph/wrapper.rb +4 -0
  136. data/lib/rails/generators/active_graph/migration/migration_generator.rb +16 -0
  137. data/lib/rails/generators/active_graph/migration/templates/migration.erb +9 -0
  138. data/lib/rails/generators/active_graph/model/model_generator.rb +89 -0
  139. data/lib/rails/generators/active_graph/model/templates/migration.erb +11 -0
  140. data/lib/rails/generators/active_graph/model/templates/model.erb +15 -0
  141. data/lib/rails/generators/active_graph/upgrade_v8/templates/migration.erb +17 -0
  142. data/lib/rails/generators/active_graph/upgrade_v8/upgrade_v8_generator.rb +34 -0
  143. data/lib/rails/generators/active_graph_generator.rb +121 -0
  144. metadata +423 -0
@@ -0,0 +1,195 @@
1
+ module ActiveGraph
2
+ module Migrations
3
+ class Runner
4
+ STATUS_TABLE_FORMAT = '%-10s %-20s %s'.freeze
5
+ SEPARATOR = '--------------------------------------------------'.freeze
6
+ FILE_MISSING = '**** file missing ****'.freeze
7
+ STATUS_TABLE_HEADER = ['Status'.freeze, 'Migration ID'.freeze, 'Migration Name'.freeze].freeze
8
+ UP_MESSAGE = 'up'.freeze
9
+ DOWN_MESSAGE = 'down'.freeze
10
+ INCOMPLETE_MESSAGE = 'incomplete'.freeze
11
+ MIGRATION_RUNNING = {up: 'running'.freeze, down: 'reverting'.freeze}.freeze
12
+ MIGRATION_DONE = {up: 'migrated'.freeze, down: 'reverted'.freeze}.freeze
13
+
14
+ def initialize(options = {})
15
+ @silenced = options[:silenced] || !!ENV['MIGRATIONS_SILENCED']
16
+ label = SchemaMigration.mapped_label
17
+ label.create_constraint(:migration_id, type: :unique) unless label.constraint?(:migration_id)
18
+ @schema_migrations = SchemaMigration.all.to_a
19
+ @up_versions = SortedSet.new(@schema_migrations.map(&:migration_id))
20
+ end
21
+
22
+ def all
23
+ handle_incomplete_states!
24
+ migration_files.each do |migration_file|
25
+ next if up?(migration_file.version)
26
+ migrate(:up, migration_file)
27
+ end
28
+ end
29
+
30
+ def up(version)
31
+ handle_incomplete_states!
32
+ migration_file = find_by_version!(version)
33
+ return if up?(version)
34
+ migrate(:up, migration_file)
35
+ end
36
+
37
+ def down(version)
38
+ handle_incomplete_states!
39
+ migration_file = find_by_version!(version)
40
+ return unless up?(version)
41
+ migrate(:down, migration_file)
42
+ end
43
+
44
+ def rollback(steps)
45
+ handle_incomplete_states!
46
+ @up_versions.to_a.reverse.first(steps).each do |version|
47
+ down(version)
48
+ end
49
+ end
50
+
51
+ def pending_migrations
52
+ all_migrations.select { |migration| !up?(migration) }
53
+ end
54
+
55
+ def complete_migration_versions
56
+ @schema_migrations.map(&:migration_id)
57
+ end
58
+
59
+ def mark_versions_as_complete(versions)
60
+ ActiveGraph::Base.new_query
61
+ .with('$versions AS versions').params(versions: versions).break
62
+ .unwind(version: :versions).break
63
+ .merge('(:`ActiveGraph::Migrations::SchemaMigration` {migration_id: version})')
64
+ .exec
65
+ end
66
+
67
+ def status
68
+ output STATUS_TABLE_FORMAT, *STATUS_TABLE_HEADER
69
+ output SEPARATOR
70
+ all_migrations.each do |version|
71
+ status = migration_status(version)
72
+ migration_file = find_by_version(version)
73
+ migration_name = migration_file ? migration_file.class_name : FILE_MISSING
74
+ output STATUS_TABLE_FORMAT, status, version, migration_name
75
+ end
76
+ end
77
+
78
+ def resolve(version)
79
+ SchemaMigration.find_by!(migration_id: version).update!(incomplete: false)
80
+ output "Migration #{version} resolved."
81
+ end
82
+
83
+ def reset(version)
84
+ SchemaMigration.find_by!(migration_id: version).destroy
85
+ output "Migration #{version} reset."
86
+ end
87
+
88
+ private
89
+
90
+ def migration_status(version)
91
+ return DOWN_MESSAGE unless up?(version)
92
+ incomplete_states.find { |v| v.migration_id == version } ? INCOMPLETE_MESSAGE : UP_MESSAGE
93
+ end
94
+
95
+ def handle_incomplete_states!
96
+ return unless incomplete_states.any?
97
+ incomplete_versions = incomplete_states.map(&:migration_id)
98
+ fail MigrationError, <<-MSG
99
+ There are migrations struck in an incomplete states, that could not be fixed automatically:
100
+ #{incomplete_versions.join('\n')}
101
+ This can happen when there's a critical error inside a migration.
102
+
103
+ If you think they were was completed correctly, run:
104
+
105
+ #{task_migration_messages('resolve', incomplete_versions)}
106
+
107
+ If you want to reset and run the migration again, run:
108
+
109
+ #{task_migration_messages('reset', incomplete_versions)}
110
+
111
+ MSG
112
+ end
113
+
114
+ def task_migration_messages(type, versions)
115
+ versions.map do |version|
116
+ "rake neo4j:migrate:#{type} VERSION=#{version}"
117
+ end.join("\n")
118
+ end
119
+
120
+ def up?(version)
121
+ @up_versions.include?(version)
122
+ end
123
+
124
+ def migrate(direction, migration_file)
125
+ migration_message(direction, migration_file) do
126
+ migration = migration_file.create(silenced: @silenced)
127
+ migration.migrate(direction)
128
+ end
129
+ end
130
+
131
+ def migration_message(direction, migration)
132
+ output_migration_message "#{migration.version} #{migration.class_name}: #{MIGRATION_RUNNING[direction]}..."
133
+ time = format('%.4fs', yield)
134
+ output_migration_message "#{migration.version} #{migration.class_name}: #{MIGRATION_DONE[direction]} (#{time})"
135
+ output ''
136
+ end
137
+
138
+ def output(*string_format)
139
+ puts format(*string_format) unless @silenced
140
+ end
141
+
142
+ def output_migration_message(message)
143
+ out = "== #{message} "
144
+ tail = '=' * [0, 80 - out.length].max
145
+ output "#{out}#{tail}"
146
+ end
147
+
148
+ def find_by_version!(version)
149
+ find_by_version(version) || fail(UnknownMigrationVersionError, "No such migration #{version}")
150
+ end
151
+
152
+ def find_by_version(version)
153
+ migration_files.find { |file| file.version == version }
154
+ end
155
+
156
+ def all_migrations
157
+ @up_versions + migration_files_versions
158
+ end
159
+
160
+ def incomplete_states
161
+ @incomplete_states ||= SortedSet.new(@schema_migrations.select(&:incomplete?))
162
+ end
163
+
164
+ delegate :migration_files, :migration_files_versions, to: :class
165
+
166
+ class <<self
167
+ def migration_files_versions
168
+ migration_files.map!(&:version)
169
+ end
170
+
171
+ def migration_files
172
+ files.map! { |file_path| MigrationFile.new(file_path) }
173
+ end
174
+
175
+ def latest_migration
176
+ migration_files.last
177
+ end
178
+
179
+ def files
180
+ Dir[files_path].sort
181
+ end
182
+
183
+ private
184
+
185
+ def files_path
186
+ app_root.join('db', 'neo4j', 'migrate', '*.rb')
187
+ end
188
+
189
+ def app_root
190
+ defined?(Rails) ? Rails.root : Pathname.new('.')
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,64 @@
1
+ module ActiveGraph
2
+ module Migrations
3
+ module Schema
4
+ class << self
5
+ def fetch_schema_data
6
+ {constraints: fetch_constraint_descriptions.sort,
7
+ indexes: fetch_index_descriptions.sort}
8
+ end
9
+
10
+ def synchronize_schema_data(schema_data, remove_missing)
11
+ queries = []
12
+ queries += drop_and_create_queries(fetch_constraint_descriptions, schema_data[:constraints], remove_missing)
13
+ queries += drop_and_create_queries(fetch_index_descriptions, schema_data[:indexes], remove_missing)
14
+ ActiveGraph::Base.write_transaction do
15
+ queries.each(&ActiveGraph::Base.method(:query))
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def fetch_constraint_descriptions
22
+ ActiveGraph::Base.query('CALL db.constraints() YIELD description').map(&:first)
23
+ end
24
+
25
+ def fetch_index_descriptions
26
+ result = ActiveGraph::Base.query('CALL db.indexes()')
27
+ if result.keys.include?(:description)
28
+ v3_indexes(result)
29
+ else
30
+ v4_indexes(result)
31
+ end
32
+ end
33
+
34
+ def v3_indexes(result)
35
+ result.reject do |row|
36
+ # These indexes are created automagically when the corresponding constraints are created
37
+ row[:type] == 'node_unique_property'
38
+ end.map { |row| row[:description] }
39
+ end
40
+
41
+ def v4_indexes(result)
42
+ result.reject do |row|
43
+ # These indexes are created automagically when the corresponding constraints are created
44
+ row[:uniqueness] == 'UNIQUE'
45
+ end.map(&method(:description))
46
+ end
47
+
48
+ def description(row)
49
+ "INDEX FOR (n:#{row[:labelsOrTypes].first}) ON (#{row[:properties].map { |prop| "n.#{prop}" }.join(', ')})"
50
+ end
51
+
52
+ def drop_and_create_queries(existing, specified, remove_missing)
53
+ [].tap do |queries|
54
+ if remove_missing
55
+ (existing - specified).each { |description| queries << "DROP #{description}" }
56
+ end
57
+
58
+ (specified - existing).each { |description| queries << "CREATE #{description}" }
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveGraph
2
+ module Migrations
3
+ class SchemaMigration
4
+ include ActiveGraph::Node
5
+ id_property :migration_id
6
+ property :migration_id, type: String
7
+ property :incomplete, type: Boolean
8
+
9
+ def <=>(other)
10
+ migration_id <=> other.migration_id
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,139 @@
1
+ require 'set'
2
+ module ActiveGraph
3
+ # This is here to support the removed functionality of being able to
4
+ # defined indexes and constraints on models
5
+ # This code should be removed later
6
+ module ModelSchema
7
+ MODEL_INDEXES = {}
8
+ MODEL_CONSTRAINTS = {}
9
+ REQUIRED_INDEXES = {}
10
+
11
+ class << self
12
+ def add_defined_constraint(model, property_name)
13
+ MODEL_CONSTRAINTS[model] ||= Set.new
14
+ MODEL_CONSTRAINTS[model] << property_name.to_sym
15
+ end
16
+
17
+ def add_defined_index(model, property_name)
18
+ MODEL_INDEXES[model] ||= Set.new
19
+ MODEL_INDEXES[model] << property_name.to_sym
20
+ end
21
+
22
+ def add_required_index(model, property_name)
23
+ REQUIRED_INDEXES[model] ||= Set.new
24
+ REQUIRED_INDEXES[model] << property_name.to_sym
25
+ end
26
+
27
+ def defined_constraint?(model, property_name)
28
+ MODEL_CONSTRAINTS[model] &&
29
+ MODEL_CONSTRAINTS[model].include?(property_name.to_sym)
30
+ end
31
+
32
+ def model_constraints
33
+ return @model_constraints if @model_constraints
34
+
35
+ constraints = ActiveGraph::Base.constraints.each_with_object({}) do |row, result|
36
+ result[row[:label]] ||= []
37
+ result[row[:label]] << row[:properties]
38
+ end
39
+
40
+ @model_constraints = schema_elements_list(MODEL_CONSTRAINTS, constraints)
41
+ end
42
+
43
+ def model_indexes
44
+ return @model_indexes if @model_indexes
45
+
46
+ indexes = ActiveGraph::Base.indexes.each_with_object({}) do |row, result|
47
+ result[row[:label]] ||= []
48
+ result[row[:label]] << row[:properties]
49
+ end
50
+
51
+ @model_indexes = schema_elements_list(MODEL_INDEXES, indexes) +
52
+ schema_elements_list(REQUIRED_INDEXES, indexes).reject(&:last)
53
+ # reject required indexes which are already in the DB
54
+ end
55
+
56
+ # should be private
57
+ def schema_elements_list(by_model, db_results)
58
+ by_model.flat_map do |model, property_names|
59
+ label = model.mapped_label_name.to_sym
60
+ property_names.map do |property_name|
61
+ exists = db_results[label] && db_results[label].include?([property_name])
62
+ [model, label, property_name, exists]
63
+ end
64
+ end
65
+ end
66
+
67
+ def ensure_model_data_state!
68
+ # If we load a new model, reset everything
69
+ if @previously_loaded_models_count != ActiveGraph::Node.loaded_classes.size
70
+ # Make sure we've finalized id_property details and have called
71
+ # add_ constraint/index methods above
72
+ ActiveGraph::Node.loaded_classes.each(&:ensure_id_property_info!)
73
+ reload_models_data!
74
+ end
75
+ end
76
+
77
+ def reload_models_data!
78
+ @previously_loaded_models_count = ActiveGraph::Node.loaded_classes.size
79
+ @model_indexes = @model_constraints = nil
80
+ end
81
+
82
+ def legacy_model_schema_informations
83
+ ensure_model_data_state!
84
+ data = {index: [], constraint: []}
85
+ each_schema_element do |type, model, label, property_name|
86
+ data[type] << {label: label, property_name: property_name, model: model}
87
+ end
88
+ data
89
+ end
90
+
91
+ def validate_model_schema!
92
+ ensure_model_data_state!
93
+ messages = {index: [], constraint: []}
94
+ each_schema_element do |type, model, label, property_name, exists|
95
+ if exists
96
+ log_warning!(type, model, property_name) if model.id_property_name.to_sym != property_name
97
+ else
98
+ messages[type] << force_add_message(type, label, property_name)
99
+ end
100
+ end
101
+
102
+ return if messages.values.all?(&:empty?)
103
+
104
+ fail ::ActiveGraph::DeprecatedSchemaDefinitionError, validation_error_message(messages)
105
+ end
106
+
107
+ def validation_error_message(messages)
108
+ <<MSG
109
+ Some schema elements were defined by the model (which is no longer supported), but they do not exist in the database. Run the following to create them if you haven't already:
110
+
111
+ #{messages[:constraint].join("\n")}
112
+ #{messages[:index].join("\n")}
113
+
114
+ And then run `rake neo4j:migrate`
115
+
116
+ (zshell users may need to escape the brackets)
117
+ MSG
118
+ end
119
+
120
+ def force_add_message(index_or_constraint, label, property_name)
121
+ "rake neo4j:generate_schema_migration[#{index_or_constraint},#{label},#{property_name}]"
122
+ end
123
+
124
+ def log_warning!(index_or_constraint, model, property_name)
125
+ ActiveGraph::Base.logger.warn "WARNING: The #{index_or_constraint} option is no longer supported (Defined on #{model.name} for #{property_name})"
126
+ end
127
+
128
+ private
129
+
130
+ def each_schema_element
131
+ [[:constraint, model_constraints], [:index, model_indexes]].each do |type, schema_elements|
132
+ schema_elements.each do |args|
133
+ yield(type, *args)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,110 @@
1
+ module ActiveGraph
2
+ # Makes Neo4j nodes and relationships behave like ActiveRecord objects.
3
+ # By including this module in your class it will create a mapping for the node to your ruby class
4
+ # by using a Neo4j Label with the same name as the class. When the node is loaded from the database it
5
+ # will check if there is a ruby class for the labels it has.
6
+ # If there Ruby class with the same name as the label then the Neo4j node will be wrapped
7
+ # in a new object of that class.
8
+ #
9
+ # = ClassMethods
10
+ # * {ActiveGraph::Node::Labels::ClassMethods} defines methods like: <tt>index</tt> and <tt>find</tt>
11
+ # * {ActiveGraph::Node::Persistence::ClassMethods} defines methods like: <tt>create</tt> and <tt>create!</tt>
12
+ # * {ActiveGraph::Node::Property::ClassMethods} defines methods like: <tt>property</tt>.
13
+ #
14
+ # @example Create a Ruby wrapper for a Neo4j Node
15
+ # class Company
16
+ # include ActiveGraph::Node
17
+ # property :name
18
+ # end
19
+ # company = Company.new
20
+ # company.name = 'My Company AB'
21
+ # Company.save
22
+ #
23
+ module Node
24
+ extend ActiveSupport::Concern
25
+
26
+ MARSHAL_INSTANCE_VARIABLES = [:@attributes, :@_persisted_obj, :@default_property_value]
27
+
28
+ include ActiveGraph::Shared
29
+ include ActiveGraph::Shared::Identity
30
+ include ActiveGraph::Shared::Marshal
31
+ include ActiveGraph::Node::Initialize
32
+ include ActiveGraph::Node::IdProperty
33
+ include ActiveGraph::Shared::SerializedProperties
34
+ include ActiveGraph::Node::Property
35
+ include ActiveGraph::Node::Reflection
36
+ include ActiveGraph::Node::Persistence
37
+ include ActiveGraph::Node::Validations
38
+ include ActiveGraph::Node::Callbacks
39
+ include ActiveGraph::Node::Query
40
+ include ActiveGraph::Node::Labels
41
+ include ActiveGraph::Node::Rels
42
+ include ActiveGraph::Node::Unpersisted
43
+ include ActiveGraph::Node::HasN
44
+ include ActiveGraph::Node::Scope
45
+ include ActiveGraph::Node::Dependent
46
+ include ActiveGraph::Node::Enum
47
+ include ActiveGraph::Shared::PermittedAttributes
48
+ include ActiveGraph::Node::DependentCallbacks
49
+ include ActiveGraph::Transactions
50
+
51
+ def initialize(args = nil)
52
+ self.class.ensure_id_property_info! # So that we make sure all objects have an id_property
53
+
54
+ args = sanitize_input_parameters(args)
55
+ super(args)
56
+ end
57
+
58
+ def neo4j_obj
59
+ _persisted_obj || fail('Tried to access native neo4j object on a non persisted object')
60
+ end
61
+
62
+ LOADED_CLASSES = []
63
+
64
+ def self.loaded_classes
65
+ LOADED_CLASSES
66
+ end
67
+
68
+ module ClassMethods
69
+ def nodeify(object)
70
+ if object.is_a?(::ActiveGraph::Node) || object.nil?
71
+ object
72
+ else
73
+ self.find(object)
74
+ end
75
+ end
76
+ end
77
+
78
+ included do
79
+ include ActiveGraph::Timestamps if ActiveGraph::Config[:record_timestamps]
80
+ LOADED_CLASSES << self
81
+
82
+ def self.inherited?
83
+ !!@inherited
84
+ end
85
+
86
+ def self.inherited(other)
87
+ ActiveGraph::Node::Labels.clear_wrapped_models
88
+
89
+ LOADED_CLASSES << other
90
+ other.instance_variable_set('@inherited', true)
91
+ inherit_id_property(other)
92
+ attributes.each_pair do |k, v|
93
+ other.inherit_property k.to_sym, v.clone, declared_properties[k].options
94
+ end
95
+
96
+ ActiveGraph::Node::Labels.add_wrapped_class(other)
97
+ super
98
+ end
99
+
100
+ def self.inherit_id_property(other)
101
+ return if other.manual_id_property? || !self.id_property?
102
+ id_prop = self.id_property_info
103
+ conf = id_prop[:type].empty? && id_prop[:name] != :neo_id ? {auto: :uuid} : id_prop[:type]
104
+ other.id_property id_prop[:name], conf, true
105
+ end
106
+ end
107
+
108
+ ActiveSupport.run_load_hooks(:node, self)
109
+ end
110
+ end