neo4apis-activerecord 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +55 -0
- data/lib/neo4apis/cli/activerecord.rb +38 -23
- data/neo4apis-activerecord.gemspec +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab9aecb11a9464f24fea4306dd70129fa149ef80
|
4
|
+
data.tar.gz: 3dfa664c481fa064e3b4ecaee0db545849f5a494
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ee71960a9de10387b975fac9cb76948398f73e1599318f4e1ff7f2133be15ed47db5858c57f716cc5b4e2736ff5efed77a16ae3ae65e14256c4cce85e349608
|
7
|
+
data.tar.gz: ea45c3c56cbbd9e114b5d2a5a46b833968d3a6cbabff9839ecc9fbaba1964ba7e555717f3eea962a883a9a181593171e115da2f9404c9729f4786feda51f9cc0
|
data/README.md
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
# neo4apis-activerecord
|
2
|
+
|
3
|
+
**The easiest and quickest way to copy data from PostgreSQL / mySQL / sqlite to Neo4j**
|
4
|
+
|
5
|
+
## How to run:
|
6
|
+
|
7
|
+
Without existing ActiveRecord application:
|
8
|
+
|
9
|
+
neo4apis activerecord all_tables --import-all-associations --identify-model
|
10
|
+
|
11
|
+
or
|
12
|
+
|
13
|
+
neo4apis activerecord tables posts comments --import-all-associations --identify-model
|
14
|
+
|
15
|
+
With existing ActiveRecord application:
|
16
|
+
|
17
|
+
neo4apis activerecord all_models --import-all-associations
|
18
|
+
|
19
|
+
or
|
20
|
+
|
21
|
+
neo4apis activerecord models Post Comment --import-all-associations
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Using rubygems:
|
26
|
+
|
27
|
+
gem install neo4apis-activerecord
|
28
|
+
|
29
|
+
## How it works
|
30
|
+
|
31
|
+
[ActiveRecord](http://guides.rubyonrails.org/active_record_basics.html) is a [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping) for ruby. `neo4apis-activerecord` uses ActiveRecord models which are either found in an existing ruby app or generated from table structures. The models are then introspected to create nodes (from tables) and relationships (from associations) in neo4j. The neo4apis library is used to load data efficiently in batches.
|
32
|
+
|
33
|
+
## Options
|
34
|
+
|
35
|
+
For a list of all options run:
|
36
|
+
|
37
|
+
neo4apis activerecord --help
|
38
|
+
|
39
|
+
### `--identify-model`
|
40
|
+
|
41
|
+
The `--identify-model` option looks for tables' names/primay keys/foreign keys automatically. Potential options are generated and the database is examined to find out which fits.
|
42
|
+
|
43
|
+
As an example: for a table of posts the following possibilities would checked:
|
44
|
+
|
45
|
+
* Names: `posts`, `post`, `Posts`, or `Post`
|
46
|
+
* Primary keys: `id`, `post_id`, `PostId`, or `uuid`
|
47
|
+
* Foreign keys: `author_id` or `AuthorId` will be assumed to go to a table of authors (with a name identified as above)
|
48
|
+
|
49
|
+
### `--import-belongs-to`
|
50
|
+
### `--import-has-many`
|
51
|
+
### `--import-has-one`
|
52
|
+
### `--import-all-associations`
|
53
|
+
|
54
|
+
Either specify that a certain class of associations be imported from ActiveRecord models or specify all with `--import-all-associations`
|
55
|
+
|
@@ -8,23 +8,25 @@ module Neo4Apis
|
|
8
8
|
class ActiveRecord < Thor
|
9
9
|
class_option :config_path, type: :string, default: 'config/database.yml'
|
10
10
|
|
11
|
-
class_option :
|
11
|
+
class_option :import_all_associations, type: :boolean, default: false, desc: 'Shortcut for --import-belongs-to --import-has-many --import-has-one'
|
12
12
|
class_option :import_belongs_to, type: :boolean, default: nil
|
13
13
|
class_option :import_has_one, type: :boolean, default: nil
|
14
14
|
class_option :import_has_many, type: :boolean, default: nil
|
15
15
|
|
16
|
-
class_option :
|
16
|
+
class_option :identify_model, type: :boolean, default: false, desc: 'Identify table name, primary key, and foreign keys automatically'
|
17
|
+
|
18
|
+
class_option :startup_environment, type: :string, default: './config/environment.rb', desc: 'Script that will be run before import. Needs to establish an ActiveRecord connection'
|
17
19
|
|
18
20
|
class_option :active_record_config_path, type: :string, default: './config/database.yml'
|
19
21
|
class_option :active_record_environment, type: :string, default: 'development'
|
20
22
|
|
21
|
-
desc 'tables MODELS_OR_TABLE_NAMES', 'Import SQL
|
23
|
+
desc 'tables MODELS_OR_TABLE_NAMES', 'Import specified SQL tables'
|
22
24
|
def tables(*models_or_table_names)
|
23
25
|
setup
|
24
26
|
|
25
27
|
model_classes = models_or_table_names.map(&method(:get_model))
|
26
28
|
|
27
|
-
puts
|
29
|
+
puts 'Importing tables: ' + model_classes.map(&:table_name).join(', ')
|
28
30
|
|
29
31
|
model_classes.each do |model_class|
|
30
32
|
::Neo4Apis::ActiveRecord.model_importer(model_class)
|
@@ -39,19 +41,28 @@ module Neo4Apis
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
44
|
+
desc 'models MODELS_OR_TABLE_NAMES', 'Import specified ActiveRecord models'
|
45
|
+
def models(*models_or_table_names)
|
46
|
+
tables(*models_or_table_names)
|
47
|
+
end
|
48
|
+
|
42
49
|
desc 'all_tables', 'Import all SQL tables'
|
43
50
|
def all_tables
|
44
|
-
|
51
|
+
tables(*::ActiveRecord::Base.connection.tables)
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'all_models', 'Import SQL tables using defined '
|
55
|
+
def all_models
|
56
|
+
Rails.application.eager_load!
|
45
57
|
|
46
|
-
|
58
|
+
tables(ActiveRecord::Base.descendants)
|
47
59
|
end
|
48
60
|
|
49
61
|
private
|
50
62
|
|
51
63
|
def setup
|
52
|
-
if File.exist?(
|
53
|
-
|
54
|
-
require './config/environment'
|
64
|
+
if File.exist?(options[:startup_environment])
|
65
|
+
require options[:startup_environment]
|
55
66
|
else
|
56
67
|
::ActiveRecord::Base.establish_connection(active_record_config)
|
57
68
|
end
|
@@ -67,16 +78,18 @@ module Neo4Apis
|
|
67
78
|
end
|
68
79
|
|
69
80
|
def import_association?(type)
|
70
|
-
options[:"import_#{type}"].nil? ? options[:
|
81
|
+
options[:"import_#{type}"].nil? ? options[:import_all_associations] : options[:"import_#{type}"]
|
71
82
|
end
|
72
83
|
|
73
84
|
|
74
85
|
def get_model(model_or_table_name)
|
86
|
+
return model_or_table_name if model_or_table_name.is_a?(ActiveRecord::Base)
|
87
|
+
|
75
88
|
get_model_class(model_or_table_name).tap do |model_class|
|
76
|
-
if options[:
|
77
|
-
|
78
|
-
|
79
|
-
|
89
|
+
if options[:identify_model]
|
90
|
+
apply_identified_table_name!(model_class)
|
91
|
+
apply_identified_primary_key!(model_class)
|
92
|
+
apply_identified_model_associations!(model_class)
|
80
93
|
end
|
81
94
|
end
|
82
95
|
end
|
@@ -89,7 +102,7 @@ module Neo4Apis
|
|
89
102
|
Object.const_set(model_class, Class.new(::ActiveRecord::Base))
|
90
103
|
end
|
91
104
|
|
92
|
-
def
|
105
|
+
def apply_identified_model_associations!(model_class)
|
93
106
|
model_class.columns.each do |column|
|
94
107
|
match = column.name.match(/^(.*)(_id|Id)$/)
|
95
108
|
next if not match
|
@@ -97,21 +110,23 @@ module Neo4Apis
|
|
97
110
|
begin
|
98
111
|
base = match[1].tableize
|
99
112
|
|
100
|
-
|
113
|
+
if identified_table_name(base.classify) && model_class.name != base.classify
|
114
|
+
model_class.belongs_to base.singularize.to_sym, foreign_key: column.name, class_name: base.classify
|
115
|
+
end
|
101
116
|
rescue NameError
|
102
117
|
end
|
103
118
|
end
|
104
119
|
end
|
105
120
|
|
106
|
-
def
|
107
|
-
|
108
|
-
model_class.table_name =
|
121
|
+
def apply_identified_table_name!(model_class)
|
122
|
+
identity = identified_table_name(model_class.name)
|
123
|
+
model_class.table_name = identity if identity
|
109
124
|
end
|
110
125
|
|
111
|
-
def
|
126
|
+
def apply_identified_primary_key!(model_class)
|
112
127
|
name = model_class.name
|
113
|
-
|
114
|
-
model_class.primary_key =
|
128
|
+
identity = (model_class.column_names & ['id', name.foreign_key, name.foreign_key.classify, 'uuid']).first
|
129
|
+
model_class.primary_key = identity if identity
|
115
130
|
end
|
116
131
|
|
117
132
|
|
@@ -122,7 +137,7 @@ module Neo4Apis
|
|
122
137
|
|
123
138
|
private
|
124
139
|
|
125
|
-
def
|
140
|
+
def identified_table_name(model_name)
|
126
141
|
(::ActiveRecord::Base.connection.tables & [model_name.tableize, model_name.classify, model_name.tableize.singularize, model_name.classify.pluralize]).first
|
127
142
|
end
|
128
143
|
end
|