activegraph 10.0.0.pre.alpha.6

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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1989 -0
  3. data/CONTRIBUTORS +12 -0
  4. data/Gemfile +24 -0
  5. data/README.md +107 -0
  6. data/bin/rake +17 -0
  7. data/config/locales/en.yml +5 -0
  8. data/config/neo4j/add_classnames.yml +1 -0
  9. data/config/neo4j/config.yml +38 -0
  10. data/lib/neo4j.rb +116 -0
  11. data/lib/neo4j/active_base.rb +89 -0
  12. data/lib/neo4j/active_node.rb +108 -0
  13. data/lib/neo4j/active_node/callbacks.rb +8 -0
  14. data/lib/neo4j/active_node/dependent.rb +11 -0
  15. data/lib/neo4j/active_node/dependent/association_methods.rb +49 -0
  16. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +51 -0
  17. data/lib/neo4j/active_node/enum.rb +26 -0
  18. data/lib/neo4j/active_node/has_n.rb +612 -0
  19. data/lib/neo4j/active_node/has_n/association.rb +278 -0
  20. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
  21. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
  22. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
  23. data/lib/neo4j/active_node/id_property.rb +224 -0
  24. data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
  25. data/lib/neo4j/active_node/initialize.rb +21 -0
  26. data/lib/neo4j/active_node/labels.rb +207 -0
  27. data/lib/neo4j/active_node/labels/index.rb +37 -0
  28. data/lib/neo4j/active_node/labels/reloading.rb +21 -0
  29. data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
  30. data/lib/neo4j/active_node/node_wrapper.rb +54 -0
  31. data/lib/neo4j/active_node/orm_adapter.rb +82 -0
  32. data/lib/neo4j/active_node/persistence.rb +187 -0
  33. data/lib/neo4j/active_node/property.rb +60 -0
  34. data/lib/neo4j/active_node/query.rb +76 -0
  35. data/lib/neo4j/active_node/query/query_proxy.rb +374 -0
  36. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +177 -0
  37. data/lib/neo4j/active_node/query/query_proxy_eager_loading/association_tree.rb +75 -0
  38. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +110 -0
  39. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
  40. data/lib/neo4j/active_node/query/query_proxy_link.rb +139 -0
  41. data/lib/neo4j/active_node/query/query_proxy_methods.rb +302 -0
  42. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +86 -0
  43. data/lib/neo4j/active_node/query_methods.rb +68 -0
  44. data/lib/neo4j/active_node/reflection.rb +86 -0
  45. data/lib/neo4j/active_node/rels.rb +11 -0
  46. data/lib/neo4j/active_node/scope.rb +166 -0
  47. data/lib/neo4j/active_node/unpersisted.rb +48 -0
  48. data/lib/neo4j/active_node/validations.rb +59 -0
  49. data/lib/neo4j/active_rel.rb +67 -0
  50. data/lib/neo4j/active_rel/callbacks.rb +15 -0
  51. data/lib/neo4j/active_rel/initialize.rb +28 -0
  52. data/lib/neo4j/active_rel/persistence.rb +134 -0
  53. data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
  54. data/lib/neo4j/active_rel/property.rb +95 -0
  55. data/lib/neo4j/active_rel/query.rb +101 -0
  56. data/lib/neo4j/active_rel/rel_wrapper.rb +31 -0
  57. data/lib/neo4j/active_rel/related_node.rb +87 -0
  58. data/lib/neo4j/active_rel/types.rb +82 -0
  59. data/lib/neo4j/active_rel/validations.rb +8 -0
  60. data/lib/neo4j/ansi.rb +14 -0
  61. data/lib/neo4j/class_arguments.rb +39 -0
  62. data/lib/neo4j/config.rb +135 -0
  63. data/lib/neo4j/core.rb +14 -0
  64. data/lib/neo4j/core/connection_failed_error.rb +6 -0
  65. data/lib/neo4j/core/cypher_error.rb +37 -0
  66. data/lib/neo4j/core/driver.rb +66 -0
  67. data/lib/neo4j/core/has_uri.rb +63 -0
  68. data/lib/neo4j/core/instrumentable.rb +36 -0
  69. data/lib/neo4j/core/label.rb +158 -0
  70. data/lib/neo4j/core/logging.rb +44 -0
  71. data/lib/neo4j/core/node.rb +23 -0
  72. data/lib/neo4j/core/querable.rb +88 -0
  73. data/lib/neo4j/core/query.rb +487 -0
  74. data/lib/neo4j/core/query_builder.rb +32 -0
  75. data/lib/neo4j/core/query_clauses.rb +727 -0
  76. data/lib/neo4j/core/query_ext.rb +24 -0
  77. data/lib/neo4j/core/query_find_in_batches.rb +49 -0
  78. data/lib/neo4j/core/relationship.rb +13 -0
  79. data/lib/neo4j/core/responses.rb +50 -0
  80. data/lib/neo4j/core/result.rb +33 -0
  81. data/lib/neo4j/core/schema.rb +30 -0
  82. data/lib/neo4j/core/schema_errors.rb +12 -0
  83. data/lib/neo4j/core/wrappable.rb +30 -0
  84. data/lib/neo4j/errors.rb +57 -0
  85. data/lib/neo4j/migration.rb +148 -0
  86. data/lib/neo4j/migrations.rb +27 -0
  87. data/lib/neo4j/migrations/base.rb +77 -0
  88. data/lib/neo4j/migrations/check_pending.rb +20 -0
  89. data/lib/neo4j/migrations/helpers.rb +105 -0
  90. data/lib/neo4j/migrations/helpers/id_property.rb +75 -0
  91. data/lib/neo4j/migrations/helpers/relationships.rb +66 -0
  92. data/lib/neo4j/migrations/helpers/schema.rb +51 -0
  93. data/lib/neo4j/migrations/migration_file.rb +24 -0
  94. data/lib/neo4j/migrations/runner.rb +195 -0
  95. data/lib/neo4j/migrations/schema.rb +44 -0
  96. data/lib/neo4j/migrations/schema_migration.rb +14 -0
  97. data/lib/neo4j/model_schema.rb +139 -0
  98. data/lib/neo4j/paginated.rb +27 -0
  99. data/lib/neo4j/railtie.rb +105 -0
  100. data/lib/neo4j/schema/operation.rb +102 -0
  101. data/lib/neo4j/shared.rb +60 -0
  102. data/lib/neo4j/shared/attributes.rb +216 -0
  103. data/lib/neo4j/shared/callbacks.rb +68 -0
  104. data/lib/neo4j/shared/cypher.rb +37 -0
  105. data/lib/neo4j/shared/declared_properties.rb +204 -0
  106. data/lib/neo4j/shared/declared_property.rb +109 -0
  107. data/lib/neo4j/shared/declared_property/index.rb +37 -0
  108. data/lib/neo4j/shared/enum.rb +167 -0
  109. data/lib/neo4j/shared/filtered_hash.rb +79 -0
  110. data/lib/neo4j/shared/identity.rb +34 -0
  111. data/lib/neo4j/shared/initialize.rb +64 -0
  112. data/lib/neo4j/shared/marshal.rb +23 -0
  113. data/lib/neo4j/shared/mass_assignment.rb +64 -0
  114. data/lib/neo4j/shared/permitted_attributes.rb +28 -0
  115. data/lib/neo4j/shared/persistence.rb +282 -0
  116. data/lib/neo4j/shared/property.rb +240 -0
  117. data/lib/neo4j/shared/query_factory.rb +102 -0
  118. data/lib/neo4j/shared/rel_type_converters.rb +43 -0
  119. data/lib/neo4j/shared/serialized_properties.rb +30 -0
  120. data/lib/neo4j/shared/type_converters.rb +433 -0
  121. data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
  122. data/lib/neo4j/shared/typecaster.rb +53 -0
  123. data/lib/neo4j/shared/validations.rb +44 -0
  124. data/lib/neo4j/tasks/migration.rake +202 -0
  125. data/lib/neo4j/timestamps.rb +11 -0
  126. data/lib/neo4j/timestamps/created.rb +9 -0
  127. data/lib/neo4j/timestamps/updated.rb +9 -0
  128. data/lib/neo4j/transaction.rb +139 -0
  129. data/lib/neo4j/type_converters.rb +7 -0
  130. data/lib/neo4j/undeclared_properties.rb +53 -0
  131. data/lib/neo4j/version.rb +3 -0
  132. data/lib/neo4j/wrapper.rb +4 -0
  133. data/lib/rails/generators/neo4j/migration/migration_generator.rb +14 -0
  134. data/lib/rails/generators/neo4j/migration/templates/migration.erb +9 -0
  135. data/lib/rails/generators/neo4j/model/model_generator.rb +88 -0
  136. data/lib/rails/generators/neo4j/model/templates/migration.erb +9 -0
  137. data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
  138. data/lib/rails/generators/neo4j/upgrade_v8/templates/migration.erb +17 -0
  139. data/lib/rails/generators/neo4j/upgrade_v8/upgrade_v8_generator.rb +32 -0
  140. data/lib/rails/generators/neo4j_generator.rb +119 -0
  141. data/neo4j.gemspec +51 -0
  142. metadata +421 -0
@@ -0,0 +1,27 @@
1
+ module Neo4j
2
+ module Migrations
3
+ extend ActiveSupport::Autoload
4
+ autoload :Helpers
5
+ autoload :MigrationFile
6
+ autoload :Base
7
+ autoload :Runner
8
+ autoload :SchemaMigration
9
+ autoload :CheckPending
10
+
11
+ class << self
12
+ def check_for_pending_migrations!
13
+ return if Neo4j::Config.configuration['skip_migration_check']
14
+
15
+ runner = Neo4j::Migrations::Runner.new
16
+ pending = runner.pending_migrations
17
+ fail ::Neo4j::PendingMigrationError, pending if pending.any?
18
+ end
19
+
20
+ attr_accessor :currently_running_migrations
21
+
22
+ def maintain_test_schema!
23
+ Neo4j::Migrations::Runner.new(silenced: true).all
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,77 @@
1
+ module Neo4j
2
+ module Migrations
3
+ class Base
4
+ include Neo4j::Migrations::Helpers
5
+ include Neo4j::Migrations::Helpers::Schema
6
+ include Neo4j::Migrations::Helpers::IdProperty
7
+ include Neo4j::Migrations::Helpers::Relationships
8
+
9
+ def initialize(migration_id, options = {})
10
+ @migration_id = migration_id
11
+ @silenced = options[:silenced]
12
+ end
13
+
14
+ def migrate(method)
15
+ Benchmark.realtime do
16
+ method == :up ? migrate_up : migrate_down
17
+ end
18
+ end
19
+
20
+ def up
21
+ fail NotImplementedError
22
+ end
23
+
24
+ def down
25
+ fail NotImplementedError
26
+ end
27
+
28
+ private
29
+
30
+ def migrate_up
31
+ schema = SchemaMigration.create!(migration_id: @migration_id, incomplete: true)
32
+ begin
33
+ run_migration(:up)
34
+ rescue StandardError => e
35
+ schema.destroy if transactions?
36
+ handle_migration_error!(e)
37
+ else
38
+ schema.update!(incomplete: nil)
39
+ end
40
+ end
41
+
42
+ def migrate_down
43
+ schema = SchemaMigration.find_by!(migration_id: @migration_id)
44
+ schema.update!(incomplete: true)
45
+ begin
46
+ run_migration(:down)
47
+ rescue StandardError => e
48
+ schema.update!(incomplete: nil) if transactions?
49
+ handle_migration_error!(e)
50
+ else
51
+ schema.destroy
52
+ end
53
+ end
54
+
55
+ def run_migration(direction)
56
+ migration_transaction { log_queries { public_send(direction) } }
57
+ end
58
+
59
+ def handle_migration_error!(e)
60
+ fail e unless e.message =~ /Cannot perform data updates in a transaction that has performed schema updates./
61
+ fail MigrationError,
62
+ "#{e.message}. Please add `disable_transactions!` in your migration file."
63
+ end
64
+
65
+ def migration_transaction(&block)
66
+ ActiveBase.run_transaction(transactions?, &block)
67
+ end
68
+
69
+ def log_queries
70
+ subscriber = Neo4j::Transaction.subscribe_to_query(&method(:output))
71
+ yield
72
+ ensure
73
+ ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,20 @@
1
+ module Neo4j
2
+ module Migrations
3
+ class CheckPending
4
+ def initialize(app)
5
+ @app = app
6
+ @last_check = 0
7
+ end
8
+
9
+ def call(env)
10
+ latest_migration = Neo4j::Migrations::Runner.latest_migration
11
+ mtime = latest_migration ? latest_migration.version.to_i : 0
12
+ if @last_check < mtime
13
+ Neo4j::Migrations.check_for_pending_migrations!
14
+ @last_check = mtime
15
+ end
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,105 @@
1
+ require 'benchmark'
2
+
3
+ module Neo4j
4
+ module Migrations
5
+ module Helpers
6
+ extend ActiveSupport::Concern
7
+ extend ActiveSupport::Autoload
8
+
9
+ autoload :Schema
10
+ autoload :IdProperty
11
+ autoload :Relationships
12
+
13
+ PROPERTY_ALREADY_DEFINED = 'Property `%{new_property}` is already defined in `%{label}`. '\
14
+ 'To overwrite, call `remove_property(:%{label}, :%{new_property})` before this method.'.freeze
15
+
16
+ def remove_property(label, property)
17
+ by_label(label).remove("n.#{property}").exec
18
+ end
19
+
20
+ def rename_property(label, old_property, new_property)
21
+ fail Neo4j::MigrationError, format(PROPERTY_ALREADY_DEFINED, new_property: new_property, label: label) if property_exists?(label, new_property)
22
+ by_label(label).set("n.#{new_property} = n.#{old_property}")
23
+ .remove("n.#{old_property}").exec
24
+ end
25
+
26
+ def drop_nodes(label)
27
+ query.match(n: label)
28
+ .optional_match('(n)-[r]-()')
29
+ .delete(:r, :n).exec
30
+ end
31
+
32
+ def add_labels(label, new_labels)
33
+ by_label(label).set(n: new_labels).exec
34
+ end
35
+
36
+ def add_label(label, new_label)
37
+ add_labels(label, [new_label])
38
+ end
39
+
40
+ def remove_labels(label, labels_to_remove)
41
+ by_label(label).remove(n: labels_to_remove).exec
42
+ end
43
+
44
+ def remove_label(label, label_to_remove)
45
+ remove_labels(label, [label_to_remove])
46
+ end
47
+
48
+ def rename_label(old_label, new_label)
49
+ by_label(old_label).set(n: new_label).remove(n: old_label).exec
50
+ end
51
+
52
+ def execute(string, params = {})
53
+ ActiveBase.query(string, params).to_a
54
+ end
55
+
56
+ def say_with_time(message)
57
+ say(message)
58
+ result = nil
59
+ time = Benchmark.measure { result = yield }
60
+ say format('%.4fs', time.real), :subitem
61
+ say("#{result} rows", :subitem) if result.is_a?(Integer)
62
+ result
63
+ end
64
+
65
+ def say(message, subitem = false)
66
+ output "#{subitem ? ' ->' : '--'} #{message}"
67
+ end
68
+
69
+ def query(*args)
70
+ ActiveBase.new_query(*args)
71
+ end
72
+
73
+ protected
74
+
75
+ def output(*string_format)
76
+ puts format(*string_format) unless @silenced
77
+ end
78
+
79
+ def transactions?
80
+ self.class.transaction?
81
+ end
82
+
83
+ private
84
+
85
+ def property_exists?(label, property)
86
+ by_label(label).where("EXISTS(n.#{property})").return(:n).any?
87
+ end
88
+
89
+ def by_label(label, options = {})
90
+ symbol = options[:symbol] || :n
91
+ query.match(symbol => label)
92
+ end
93
+
94
+ module ClassMethods
95
+ def disable_transactions!
96
+ @disable_transactions = true
97
+ end
98
+
99
+ def transaction?
100
+ !@disable_transactions
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,75 @@
1
+ module Neo4j
2
+ module Migrations
3
+ module Helpers
4
+ module IdProperty
5
+ extend ActiveSupport::Concern
6
+
7
+ def populate_id_property(label)
8
+ model = label.to_s.constantize
9
+ max_per_batch = (ENV['MAX_PER_BATCH'] || default_max_per_batch).to_i
10
+
11
+ last_time_taken = nil
12
+
13
+ until (nodes_left = idless_count(label, model.primary_key)) == 0
14
+ print_status(last_time_taken, max_per_batch, nodes_left)
15
+
16
+ count = [nodes_left, max_per_batch].min
17
+ last_time_taken = Benchmark.realtime do
18
+ max_per_batch = id_batch_set(label, model.primary_key, Array.new(count) { new_id_for(model) }, count)
19
+ end
20
+ end
21
+ end
22
+
23
+ protected
24
+
25
+ def idless_count(label, id_property)
26
+ query.match(n: label).where("NOT EXISTS(n.#{id_property})").pluck('COUNT(n) AS ids').first
27
+ end
28
+
29
+ def id_batch_set(label, id_property, new_ids, count)
30
+ tx = ActiveBase.new_transaction
31
+
32
+ execute("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
33
+ with COLLECT(n) as nodes, #{new_ids} as ids
34
+ FOREACH(i in range(0,#{count - 1})|
35
+ FOREACH(node in [nodes[i]]|
36
+ SET node.#{id_property} = ids[i]))
37
+ RETURN distinct(true)
38
+ LIMIT #{count}")
39
+
40
+ count
41
+ rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
42
+ new_max_per_batch = (max_per_batch * 0.8).round
43
+ output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
44
+ new_max_per_batch
45
+ ensure
46
+ tx.close
47
+ end
48
+
49
+ def print_status(last_time_taken, max_per_batch, nodes_left)
50
+ time_per_node = last_time_taken / max_per_batch if last_time_taken
51
+ message = if time_per_node
52
+ eta_seconds = (nodes_left * time_per_node).round
53
+ "#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)"
54
+ else
55
+ 'Running first batch...'
56
+ end
57
+
58
+ output message
59
+ end
60
+
61
+ def default_max_per_batch
62
+ 900
63
+ end
64
+
65
+ def new_id_for(model)
66
+ if model.id_property_info[:type][:auto]
67
+ SecureRandom.uuid
68
+ else
69
+ model.new.send(model.id_property_info[:type][:on])
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,66 @@
1
+ module Neo4j
2
+ module Migrations
3
+ module Helpers
4
+ module Relationships
5
+ extend ActiveSupport::Concern
6
+
7
+ DEFAULT_MAX_PER_BATCH = 1000
8
+
9
+ def change_relations_style(relationships, old_style, new_style, params = {})
10
+ relationships.each do |rel|
11
+ relabel_relation(relationship_style(rel, old_style), relationship_style(rel, new_style), params)
12
+ end
13
+ end
14
+
15
+ def relabel_relation(old_name, new_name, params = {})
16
+ relation_query = match_relation(old_name, params)
17
+
18
+ max_per_batch = (ENV['MAX_PER_BATCH'] || DEFAULT_MAX_PER_BATCH).to_i
19
+
20
+ count = count_relations(relation_query)
21
+ output "Indexing #{count} #{old_name}s into #{new_name}..."
22
+ while count > 0
23
+ relation_query.create("(a)-[r2:`#{new_name}`]->(b)").set('r2 = r').with(:r).limit(max_per_batch).delete(:r).exec
24
+ count = count_relations(relation_query)
25
+ output "... #{count} #{old_name}'s left to go.." if count > 0
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def match_relation(label, params = {})
32
+ from = params[:from] ? "(a:`#{params[:from]}`)" : '(a)'
33
+ to = params[:to] ? "(b:`#{params[:to]}`)" : '(b)'
34
+ relation = arrow_cypher(label, params[:direction])
35
+
36
+ query.match("#{from}#{relation}#{to}")
37
+ end
38
+
39
+ def arrow_cypher(label, direction)
40
+ case direction
41
+ when :in
42
+ "<-[r:`#{label}`]-"
43
+ when :both
44
+ "<-[r:`#{label}`]->"
45
+ else
46
+ "-[r:`#{label}`]->"
47
+ end
48
+ end
49
+
50
+ def count_relations(query)
51
+ query.pluck('COUNT(r)').first
52
+ end
53
+
54
+ def relationship_style(relationship, format)
55
+ case format.to_s
56
+ when 'lower_hashtag' then "##{relationship.downcase}"
57
+ when 'lower' then relationship.downcase
58
+ when 'upper' then relationship.upcase
59
+ else
60
+ fail("Invalid relationship type style `#{format}`.")
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,51 @@
1
+ module Neo4j
2
+ module Migrations
3
+ module Helpers
4
+ module Schema
5
+ extend ActiveSupport::Concern
6
+ MISSING_CONSTRAINT_OR_INDEX = 'No such %{type} for %{label}#%{property}'.freeze
7
+ DUPLICATE_CONSTRAINT_OR_INDEX = 'Duplicate %{type} for %{label}#%{property}'.freeze
8
+
9
+ def add_constraint(label, property, options = {})
10
+ force = options[:force] || false
11
+ type = options[:type] || :uniqueness
12
+ label_object = ActiveBase.label_object(label)
13
+ fail_duplicate_constraint_or_index!(:constraint, label, property) if !force && label_object.constraint?(property)
14
+ label_object.create_constraint(property, type: type)
15
+ end
16
+
17
+ def add_index(label, property, options = {})
18
+ force = options[:force] || false
19
+ label_object = ActiveBase.label_object(label)
20
+ fail_duplicate_constraint_or_index!(:index, label, property) if !force && label_object.index?(property)
21
+ label_object.create_index(property)
22
+ end
23
+
24
+ def drop_constraint(label, property, options = {})
25
+ type = options[:type] || :uniqueness
26
+ label_object = ActiveBase.label_object(label)
27
+ fail_missing_constraint_or_index!(:constraint, label, property) if !options[:force] && !label_object.constraint?(property)
28
+ label_object.drop_constraint(property, type: type)
29
+ end
30
+
31
+ def drop_index(label, property, options = {})
32
+ label_object = ActiveBase.label_object(label)
33
+ fail_missing_constraint_or_index!(:index, label, property) if !options[:force] && !label_object.index?(property)
34
+ label_object.drop_index(property)
35
+ end
36
+
37
+ protected
38
+
39
+ def fail_missing_constraint_or_index!(type, label, property)
40
+ fail Neo4j::MigrationError,
41
+ format(MISSING_CONSTRAINT_OR_INDEX, type: type, label: label, property: property)
42
+ end
43
+
44
+ def fail_duplicate_constraint_or_index!(type, label, property)
45
+ fail Neo4j::MigrationError,
46
+ format(DUPLICATE_CONSTRAINT_OR_INDEX, type: type, label: label, property: property)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ module Neo4j
2
+ module Migrations
3
+ class MigrationFile
4
+ attr_reader :file_name, :symbol_name, :class_name, :version
5
+
6
+ def initialize(file_name)
7
+ @file_name = file_name
8
+ extract_data!
9
+ end
10
+
11
+ def create(options = {})
12
+ require @file_name
13
+ class_name.constantize.new(@version, options)
14
+ end
15
+
16
+ private
17
+
18
+ def extract_data!
19
+ @version, @symbol_name = File.basename(@file_name, '.rb').split('_', 2)
20
+ @class_name = @symbol_name.camelize
21
+ end
22
+ end
23
+ end
24
+ end