activegraph 11.0.0.beta.1-java
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 +7 -0
- data/CHANGELOG.md +2016 -0
- data/CONTRIBUTORS +12 -0
- data/Gemfile +24 -0
- data/README.md +111 -0
- data/activegraph.gemspec +52 -0
- data/bin/rake +17 -0
- data/config/locales/en.yml +5 -0
- data/config/neo4j/add_classnames.yml +1 -0
- data/config/neo4j/config.yml +35 -0
- data/lib/active_graph.rb +123 -0
- data/lib/active_graph/ansi.rb +14 -0
- data/lib/active_graph/attribute_set.rb +32 -0
- data/lib/active_graph/base.rb +77 -0
- data/lib/active_graph/class_arguments.rb +39 -0
- data/lib/active_graph/config.rb +135 -0
- data/lib/active_graph/core.rb +14 -0
- data/lib/active_graph/core/connection_failed_error.rb +6 -0
- data/lib/active_graph/core/cypher_error.rb +37 -0
- data/lib/active_graph/core/entity.rb +11 -0
- data/lib/active_graph/core/instrumentable.rb +37 -0
- data/lib/active_graph/core/label.rb +135 -0
- data/lib/active_graph/core/logging.rb +44 -0
- data/lib/active_graph/core/node.rb +15 -0
- data/lib/active_graph/core/querable.rb +41 -0
- data/lib/active_graph/core/query.rb +485 -0
- data/lib/active_graph/core/query_builder.rb +18 -0
- data/lib/active_graph/core/query_clauses.rb +727 -0
- data/lib/active_graph/core/query_ext.rb +24 -0
- data/lib/active_graph/core/query_find_in_batches.rb +46 -0
- data/lib/active_graph/core/record.rb +51 -0
- data/lib/active_graph/core/result.rb +31 -0
- data/lib/active_graph/core/schema.rb +65 -0
- data/lib/active_graph/core/schema_errors.rb +12 -0
- data/lib/active_graph/core/wrappable.rb +30 -0
- data/lib/active_graph/errors.rb +59 -0
- data/lib/active_graph/lazy_attribute_hash.rb +38 -0
- data/lib/active_graph/migration.rb +148 -0
- data/lib/active_graph/migrations.rb +27 -0
- data/lib/active_graph/migrations/base.rb +77 -0
- data/lib/active_graph/migrations/check_pending.rb +20 -0
- data/lib/active_graph/migrations/helpers.rb +105 -0
- data/lib/active_graph/migrations/helpers/id_property.rb +72 -0
- data/lib/active_graph/migrations/helpers/relationships.rb +66 -0
- data/lib/active_graph/migrations/helpers/schema.rb +63 -0
- data/lib/active_graph/migrations/migration_file.rb +24 -0
- data/lib/active_graph/migrations/runner.rb +195 -0
- data/lib/active_graph/migrations/schema.rb +64 -0
- data/lib/active_graph/migrations/schema_migration.rb +14 -0
- data/lib/active_graph/model_schema.rb +139 -0
- data/lib/active_graph/node.rb +110 -0
- data/lib/active_graph/node/callbacks.rb +8 -0
- data/lib/active_graph/node/dependent.rb +11 -0
- data/lib/active_graph/node/dependent/association_methods.rb +49 -0
- data/lib/active_graph/node/dependent/query_proxy_methods.rb +52 -0
- data/lib/active_graph/node/dependent_callbacks.rb +31 -0
- data/lib/active_graph/node/enum.rb +26 -0
- data/lib/active_graph/node/has_n.rb +602 -0
- data/lib/active_graph/node/has_n/association.rb +278 -0
- data/lib/active_graph/node/has_n/association/rel_factory.rb +61 -0
- data/lib/active_graph/node/has_n/association/rel_wrapper.rb +23 -0
- data/lib/active_graph/node/has_n/association_cypher_methods.rb +108 -0
- data/lib/active_graph/node/id_property.rb +224 -0
- data/lib/active_graph/node/id_property/accessor.rb +62 -0
- data/lib/active_graph/node/initialize.rb +21 -0
- data/lib/active_graph/node/labels.rb +207 -0
- data/lib/active_graph/node/labels/index.rb +37 -0
- data/lib/active_graph/node/labels/reloading.rb +21 -0
- data/lib/active_graph/node/node_list_formatter.rb +13 -0
- data/lib/active_graph/node/node_wrapper.rb +54 -0
- data/lib/active_graph/node/orm_adapter.rb +82 -0
- data/lib/active_graph/node/persistence.rb +186 -0
- data/lib/active_graph/node/property.rb +60 -0
- data/lib/active_graph/node/query.rb +76 -0
- data/lib/active_graph/node/query/query_proxy.rb +367 -0
- data/lib/active_graph/node/query/query_proxy_eager_loading.rb +177 -0
- data/lib/active_graph/node/query/query_proxy_eager_loading/association_tree.rb +75 -0
- data/lib/active_graph/node/query/query_proxy_enumerable.rb +110 -0
- data/lib/active_graph/node/query/query_proxy_find_in_batches.rb +19 -0
- data/lib/active_graph/node/query/query_proxy_link.rb +139 -0
- data/lib/active_graph/node/query/query_proxy_methods.rb +303 -0
- data/lib/active_graph/node/query/query_proxy_methods_of_mass_updating.rb +99 -0
- data/lib/active_graph/node/query_methods.rb +68 -0
- data/lib/active_graph/node/reflection.rb +86 -0
- data/lib/active_graph/node/rels.rb +11 -0
- data/lib/active_graph/node/scope.rb +166 -0
- data/lib/active_graph/node/unpersisted.rb +48 -0
- data/lib/active_graph/node/validations.rb +59 -0
- data/lib/active_graph/paginated.rb +27 -0
- data/lib/active_graph/railtie.rb +108 -0
- data/lib/active_graph/relationship.rb +68 -0
- data/lib/active_graph/relationship/callbacks.rb +21 -0
- data/lib/active_graph/relationship/initialize.rb +28 -0
- data/lib/active_graph/relationship/persistence.rb +133 -0
- data/lib/active_graph/relationship/persistence/query_factory.rb +95 -0
- data/lib/active_graph/relationship/property.rb +92 -0
- data/lib/active_graph/relationship/query.rb +99 -0
- data/lib/active_graph/relationship/rel_wrapper.rb +31 -0
- data/lib/active_graph/relationship/related_node.rb +87 -0
- data/lib/active_graph/relationship/types.rb +80 -0
- data/lib/active_graph/relationship/validations.rb +8 -0
- data/lib/active_graph/schema/operation.rb +102 -0
- data/lib/active_graph/shared.rb +48 -0
- data/lib/active_graph/shared/attributes.rb +217 -0
- data/lib/active_graph/shared/callbacks.rb +66 -0
- data/lib/active_graph/shared/cypher.rb +37 -0
- data/lib/active_graph/shared/declared_properties.rb +204 -0
- data/lib/active_graph/shared/declared_property.rb +109 -0
- data/lib/active_graph/shared/declared_property/index.rb +37 -0
- data/lib/active_graph/shared/enum.rb +167 -0
- data/lib/active_graph/shared/filtered_hash.rb +79 -0
- data/lib/active_graph/shared/identity.rb +34 -0
- data/lib/active_graph/shared/initialize.rb +65 -0
- data/lib/active_graph/shared/marshal.rb +23 -0
- data/lib/active_graph/shared/mass_assignment.rb +63 -0
- data/lib/active_graph/shared/permitted_attributes.rb +28 -0
- data/lib/active_graph/shared/persistence.rb +272 -0
- data/lib/active_graph/shared/property.rb +249 -0
- data/lib/active_graph/shared/query_factory.rb +122 -0
- data/lib/active_graph/shared/rel_type_converters.rb +43 -0
- data/lib/active_graph/shared/serialized_properties.rb +30 -0
- data/lib/active_graph/shared/type_converters.rb +439 -0
- data/lib/active_graph/shared/typecasted_attributes.rb +99 -0
- data/lib/active_graph/shared/typecaster.rb +53 -0
- data/lib/active_graph/shared/validations.rb +44 -0
- data/lib/active_graph/tasks/migration.rake +204 -0
- data/lib/active_graph/timestamps.rb +11 -0
- data/lib/active_graph/timestamps/created.rb +9 -0
- data/lib/active_graph/timestamps/updated.rb +9 -0
- data/lib/active_graph/transaction.rb +22 -0
- data/lib/active_graph/transactions.rb +57 -0
- data/lib/active_graph/type_converters.rb +7 -0
- data/lib/active_graph/undeclared_properties.rb +53 -0
- data/lib/active_graph/version.rb +3 -0
- data/lib/active_graph/wrapper.rb +4 -0
- data/lib/rails/generators/active_graph/migration/migration_generator.rb +16 -0
- data/lib/rails/generators/active_graph/migration/templates/migration.erb +9 -0
- data/lib/rails/generators/active_graph/model/model_generator.rb +89 -0
- data/lib/rails/generators/active_graph/model/templates/migration.erb +11 -0
- data/lib/rails/generators/active_graph/model/templates/model.erb +15 -0
- data/lib/rails/generators/active_graph/upgrade_v8/templates/migration.erb +17 -0
- data/lib/rails/generators/active_graph/upgrade_v8/upgrade_v8_generator.rb +34 -0
- data/lib/rails/generators/active_graph_generator.rb +121 -0
- metadata +423 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module ActiveGraph
|
|
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 ActiveGraph::Config.configuration['skip_migration_check']
|
|
14
|
+
|
|
15
|
+
runner = ActiveGraph::Migrations::Runner.new
|
|
16
|
+
pending = runner.pending_migrations
|
|
17
|
+
fail ::ActiveGraph::PendingMigrationError, pending if pending.any?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
attr_accessor :currently_running_migrations
|
|
21
|
+
|
|
22
|
+
def maintain_test_schema!
|
|
23
|
+
ActiveGraph::Migrations::Runner.new(silenced: true).all
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module ActiveGraph
|
|
2
|
+
module Migrations
|
|
3
|
+
class Base
|
|
4
|
+
include ActiveGraph::Migrations::Helpers
|
|
5
|
+
include ActiveGraph::Migrations::Helpers::Schema
|
|
6
|
+
include ActiveGraph::Migrations::Helpers::IdProperty
|
|
7
|
+
include ActiveGraph::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
|
+
transactions? ? ActiveGraph::Base.transaction(&block) : block.call
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def log_queries
|
|
70
|
+
subscriber = ActiveGraph::Base.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 ActiveGraph
|
|
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 = ActiveGraph::Migrations::Runner.latest_migration
|
|
11
|
+
mtime = latest_migration ? latest_migration.version.to_i : 0
|
|
12
|
+
if @last_check < mtime
|
|
13
|
+
ActiveGraph::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 ActiveGraph
|
|
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 ActiveGraph::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
|
+
ActiveGraph::Base.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
|
+
ActiveGraph::Base.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,72 @@
|
|
|
1
|
+
module ActiveGraph
|
|
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
|
+
ActiveGraph::Base.transaction do
|
|
31
|
+
execute("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
|
|
32
|
+
with COLLECT(n) as nodes, #{new_ids} as ids
|
|
33
|
+
FOREACH(i in range(0,#{count - 1})|
|
|
34
|
+
FOREACH(node in [nodes[i]]|
|
|
35
|
+
SET node.#{id_property} = ids[i]))
|
|
36
|
+
RETURN distinct(true)
|
|
37
|
+
LIMIT #{count}")
|
|
38
|
+
count
|
|
39
|
+
end
|
|
40
|
+
rescue ActiveGraph::Server::CypherResponse::ResponseError
|
|
41
|
+
new_max_per_batch = (max_per_batch * 0.8).round
|
|
42
|
+
output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
|
|
43
|
+
new_max_per_batch
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def print_status(last_time_taken, max_per_batch, nodes_left)
|
|
47
|
+
time_per_node = last_time_taken / max_per_batch if last_time_taken
|
|
48
|
+
message = if time_per_node
|
|
49
|
+
eta_seconds = (nodes_left * time_per_node).round
|
|
50
|
+
"#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)"
|
|
51
|
+
else
|
|
52
|
+
'Running first batch...'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
output message
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def default_max_per_batch
|
|
59
|
+
900
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def new_id_for(model)
|
|
63
|
+
if model.id_property_info[:type][:auto]
|
|
64
|
+
SecureRandom.uuid
|
|
65
|
+
else
|
|
66
|
+
model.new.send(model.id_property_info[:type][:on])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module ActiveGraph
|
|
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,63 @@
|
|
|
1
|
+
module ActiveGraph
|
|
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 = ActiveGraph::Base.label_object(label)
|
|
13
|
+
if label_object.constraint?(property)
|
|
14
|
+
if force
|
|
15
|
+
label_object.drop_constraint(property, type: type)
|
|
16
|
+
else
|
|
17
|
+
fail_duplicate_constraint_or_index!(:constraint, label, property)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
label_object.create_constraint(property, type: type)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def add_index(label, property, options = {})
|
|
24
|
+
force = options[:force] || false
|
|
25
|
+
label_object = ActiveGraph::Base.label_object(label)
|
|
26
|
+
if label_object.index?(property)
|
|
27
|
+
if force
|
|
28
|
+
label_object.drop_index(property)
|
|
29
|
+
else
|
|
30
|
+
fail_duplicate_constraint_or_index!(:index, label, property)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
label_object.create_index(property)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def drop_constraint(label, property, options = {})
|
|
37
|
+
type = options[:type] || :uniqueness
|
|
38
|
+
label_object = ActiveGraph::Base.label_object(label)
|
|
39
|
+
fail_missing_constraint_or_index!(:constraint, label, property) if !options[:force] && !label_object.constraint?(property)
|
|
40
|
+
label_object.drop_constraint(property, type: type)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def drop_index(label, property, options = {})
|
|
44
|
+
label_object = ActiveGraph::Base.label_object(label)
|
|
45
|
+
fail_missing_constraint_or_index!(:index, label, property) if !options[:force] && !label_object.index?(property)
|
|
46
|
+
label_object.drop_index(property)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def fail_missing_constraint_or_index!(type, label, property)
|
|
52
|
+
fail ActiveGraph::MigrationError,
|
|
53
|
+
format(MISSING_CONSTRAINT_OR_INDEX, type: type, label: label, property: property)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def fail_duplicate_constraint_or_index!(type, label, property)
|
|
57
|
+
fail ActiveGraph::MigrationError,
|
|
58
|
+
format(DUPLICATE_CONSTRAINT_OR_INDEX, type: type, label: label, property: property)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module ActiveGraph
|
|
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
|