rare_map 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +3 -19
- data/lib/rare_map.rb +13 -3
- data/lib/rare_map/column.rb +42 -0
- data/lib/rare_map/config_loader.rb +18 -69
- data/lib/rare_map/database_profile.rb +32 -0
- data/lib/rare_map/errors.rb +7 -1
- data/lib/rare_map/model.rb +48 -0
- data/lib/rare_map/model_builder.rb +12 -29
- data/lib/rare_map/model_generator.rb +12 -8
- data/lib/rare_map/options.rb +78 -0
- data/lib/rare_map/rails_locator.rb +14 -6
- data/lib/rare_map/relation.rb +41 -0
- data/lib/rare_map/schema_parser.rb +7 -71
- data/lib/rare_map/schema_reader.rb +7 -0
- data/lib/rare_map/table.rb +89 -0
- data/lib/rare_map/version.rb +7 -3
- data/test/column_test.rb +29 -0
- data/test/config_loader_test.rb +34 -0
- data/test/database_profile_test.rb +25 -0
- data/test/model_builder_test.rb +22 -0
- data/test/model_test.rb +40 -0
- data/test/options_test.rb +54 -0
- data/test/rails_locator_test.rb +12 -0
- data/test/rare_map.yml +16 -0
- data/test/rare_map_simple.yml +14 -0
- data/test/rare_map_test.rb +1 -3
- data/test/relation_test.rb +29 -0
- data/test/schema_parser_test.rb +28 -0
- data/test/table_test.rb +51 -0
- data/test/{helper.rb → test_helper.rb} +7 -1
- metadata +50 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2a5bcbd97c37310f2e809a4328490c44076bd06
|
4
|
+
data.tar.gz: f7fb2de31bbf07022673ad8a3e4655351f902e8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 839fb36c3ea95902213b7b2507ba2231b1238cee119fc9703a44af158b948d9add23725f2208f992623e7f472e7c1eefb94c23cce6e108435733f2da77044d1c
|
7
|
+
data.tar.gz: 8c1f2ccfe9102b00e9b43f03004a16a5f8e2e141e79cd107f7b0d5e3bd16c7fda53122dc2e4abd92d37d920e5c0976817bfa3c8c8b888b24297188cc4ec44186
|
data/Rakefile
CHANGED
@@ -4,24 +4,9 @@ begin
|
|
4
4
|
rescue LoadError
|
5
5
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
6
|
end
|
7
|
-
begin
|
8
|
-
require 'rdoc/task'
|
9
|
-
rescue LoadError
|
10
|
-
require 'rdoc/rdoc'
|
11
|
-
require 'rake/rdoctask'
|
12
|
-
RDoc::Task = Rake::RDocTask
|
13
|
-
end
|
14
|
-
|
15
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
-
rdoc.rdoc_dir = 'rdoc'
|
17
|
-
rdoc.title = 'RareMap'
|
18
|
-
rdoc.options << '--line-numbers'
|
19
|
-
rdoc.rdoc_files.include('README.rdoc')
|
20
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
7
|
|
8
|
+
require 'yard'
|
9
|
+
YARD::Rake::YardocTask.new
|
25
10
|
|
26
11
|
Bundler::GemHelper.install_tasks
|
27
12
|
|
@@ -34,5 +19,4 @@ Rake::TestTask.new(:test) do |t|
|
|
34
19
|
t.verbose = false
|
35
20
|
end
|
36
21
|
|
37
|
-
|
38
|
-
task :default => :test
|
22
|
+
task :default => :test
|
data/lib/rare_map.rb
CHANGED
@@ -5,20 +5,29 @@ require 'rare_map/schema_parser'
|
|
5
5
|
require 'rare_map/model_builder'
|
6
6
|
require 'rare_map/model_generator'
|
7
7
|
|
8
|
+
# RareMap
|
9
|
+
# @author Wei-Ming Wu
|
8
10
|
module RareMap
|
11
|
+
# A class method to make RareMap::Mapper#mapping easy to be called.
|
9
12
|
def self.mapping
|
10
13
|
Mapper.new.mapping
|
11
14
|
end
|
12
15
|
|
16
|
+
# RareMap::Mapper converts relational databases into ActiveRecord files.
|
17
|
+
# @author Wei-Ming Wu
|
13
18
|
class Mapper
|
14
19
|
include RailsLocator, ConfigLoader, SchemaReader, SchemaParser, ModelBuilder, ModelGenerator
|
15
20
|
|
21
|
+
# Creates a Mapper.
|
22
|
+
#
|
23
|
+
# @return [Mapper] a Mapper object
|
16
24
|
def initialize
|
17
25
|
@rails_root = locate_rails_root
|
18
26
|
end
|
19
27
|
|
28
|
+
# Converts relational databases into ActiveRecord files by given RareMap config yaml file.
|
20
29
|
def mapping
|
21
|
-
@db_profiles = load_config @rails_root ? @rails_root
|
30
|
+
@db_profiles = load_config @rails_root ? File.join(@rails_root, 'config') : '.'
|
22
31
|
@db_profiles.each do |profile|
|
23
32
|
profile.schema = read_schema profile
|
24
33
|
profile.tables = parse_schema profile.schema
|
@@ -37,11 +46,12 @@ module RareMap
|
|
37
46
|
end
|
38
47
|
@models
|
39
48
|
|
40
|
-
|
41
|
-
|
49
|
+
rescue ConfigNotFoundError => e
|
50
|
+
puts "Please put your database config in `#{'config/' if @rails_root}rare_map.yml`."
|
42
51
|
end
|
43
52
|
|
44
53
|
private
|
54
|
+
|
45
55
|
def generate_demo
|
46
56
|
f = File.new('demo.rb', 'w')
|
47
57
|
f.write "require 'active_record'\n"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RareMap
|
2
|
+
# RareMap::Column defines a column of a database table.
|
3
|
+
# @author Wei-Ming Wu
|
4
|
+
# @!attribute [r] name
|
5
|
+
# @return [String] the name of this Column
|
6
|
+
# @!attribute [r] type
|
7
|
+
# @return [String] the type of this Column
|
8
|
+
# @!attribute unique
|
9
|
+
# @return [true, false] the uniqueness of this Column
|
10
|
+
# @!attribute ref_table
|
11
|
+
# @return [String] the reference table of this Column
|
12
|
+
class Column
|
13
|
+
attr_reader :name, :type
|
14
|
+
attr_accessor :unique
|
15
|
+
attr_accessor :ref_table
|
16
|
+
|
17
|
+
# Creates a Column.
|
18
|
+
#
|
19
|
+
# @param name [String] the name of column
|
20
|
+
# @param type [String] the type of column
|
21
|
+
# @return [Column] a Column object
|
22
|
+
def initialize(name, type, opts = {})
|
23
|
+
@name = name
|
24
|
+
@type = type
|
25
|
+
@unique = opts[:unique] == true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checks if this Column is unique.
|
29
|
+
#
|
30
|
+
# @return [true, false] true if it's unique, false otherwise
|
31
|
+
def unique?
|
32
|
+
@unique
|
33
|
+
end
|
34
|
+
|
35
|
+
# Checks if this Column is a foreign key.
|
36
|
+
#
|
37
|
+
# @return [true, false] true if it's a foreign key, false otherwise
|
38
|
+
def foreign_key?
|
39
|
+
@ref_table ? true : false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,17 +1,29 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'rare_map/errors'
|
3
|
+
require 'rare_map/database_profile'
|
4
|
+
require 'rare_map/options'
|
3
5
|
|
4
6
|
module RareMap
|
7
|
+
# RareMap::ConfigLoader translates a rare_map.yml into DatabaseProfile.
|
8
|
+
# @author Wei-Ming Wu
|
5
9
|
module ConfigLoader
|
10
|
+
# The key of rare map options inside a config YAML.
|
6
11
|
OPTS_KEY = 'rare_map_opts'
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
include Errors
|
13
|
+
|
14
|
+
# Translates a rare_map.yaml into an Array of DatabaseProfile.
|
15
|
+
#
|
16
|
+
# @param [String] path the folder which contains the RareMap config
|
17
|
+
# @param [String] file_name the name of the RareMap config
|
18
|
+
# @return [Array] an Array of DatabaseProfile
|
19
|
+
def load_config(path = '.', file_name = 'rare_map.yml')
|
20
|
+
raise ConfigNotFoundError unless File.exist? File.join(path, file_name)
|
21
|
+
config = YAML.load_file File.join(path, file_name)
|
11
22
|
organize_config_properties config['rare_map'] || config || {}
|
12
23
|
end
|
13
24
|
|
14
25
|
private
|
26
|
+
|
15
27
|
def organize_config_properties(raw_config)
|
16
28
|
db_profiles = []
|
17
29
|
global_opts = Options.new(raw_config.delete OPTS_KEY)
|
@@ -26,11 +38,11 @@ module RareMap
|
|
26
38
|
end
|
27
39
|
when 'Array'
|
28
40
|
v = v.reduce(:merge)
|
29
|
-
group_opts = Options.new(v.delete(OPTS_KEY) || global_opts.opts
|
41
|
+
group_opts = Options.new((v.delete(OPTS_KEY) || global_opts.opts).merge(group: k))
|
30
42
|
|
31
43
|
v.each do |db, config|
|
32
44
|
if config[OPTS_KEY]
|
33
|
-
db_profiles << DatabaseProfile.new(db, remove_opts(config), Options.new(config[OPTS_KEY]
|
45
|
+
db_profiles << DatabaseProfile.new(db, remove_opts(config), Options.new(config[OPTS_KEY].merge(group: k)))
|
34
46
|
else
|
35
47
|
db_profiles << DatabaseProfile.new(db, config, group_opts)
|
36
48
|
end
|
@@ -45,67 +57,4 @@ module RareMap
|
|
45
57
|
db.select { |k, _| k != OPTS_KEY }
|
46
58
|
end
|
47
59
|
end
|
48
|
-
|
49
|
-
class DatabaseProfile
|
50
|
-
attr_reader :name, :connection, :options
|
51
|
-
attr_accessor :schema, :tables
|
52
|
-
|
53
|
-
def initialize(name, connection, options)
|
54
|
-
@name, @connection = name, connection
|
55
|
-
@options = options || Options.new
|
56
|
-
@tables = []
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Options
|
61
|
-
attr_reader :opts
|
62
|
-
|
63
|
-
def initialize(raw_opts = nil, group = nil)
|
64
|
-
@opts = { 'group' => 'default',
|
65
|
-
'primary_key' => {},
|
66
|
-
'foreign_key' => { 'suffix' => nil, 'alias' => {} } }
|
67
|
-
|
68
|
-
if raw_opts and raw_opts.kind_of? Hash
|
69
|
-
if raw_opts['group']
|
70
|
-
@opts['group'] = raw_opts['group']
|
71
|
-
end
|
72
|
-
if raw_opts['primary_key'].kind_of? Hash
|
73
|
-
@opts['primary_key'] = raw_opts['primary_key'].select { |k, v| k.kind_of? String and v.kind_of? String }
|
74
|
-
end
|
75
|
-
if raw_opts['foreign_key'] and raw_opts['foreign_key']['suffix'].kind_of? String
|
76
|
-
@opts['foreign_key']['suffix'] = raw_opts['foreign_key']['suffix']
|
77
|
-
end
|
78
|
-
if raw_opts['foreign_key'] and raw_opts['foreign_key']['alias'].kind_of? Hash
|
79
|
-
@opts['foreign_key']['alias'] = raw_opts['foreign_key']['alias'].select { |k, v| k.kind_of? String and v.kind_of? String }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
@opts['group'] = group if group.kind_of? String
|
83
|
-
end
|
84
|
-
|
85
|
-
def group?
|
86
|
-
@opts['group'] != 'default'
|
87
|
-
end
|
88
|
-
|
89
|
-
def group
|
90
|
-
@opts['group'] || 'default'
|
91
|
-
end
|
92
|
-
|
93
|
-
def find_primary_key_by_table(table_name)
|
94
|
-
@opts['primary_key'].each { |k, v| return v if k == table_name }
|
95
|
-
nil
|
96
|
-
end
|
97
|
-
|
98
|
-
def find_table_by_foreign_key(column_name)
|
99
|
-
@opts['foreign_key']['alias'].each { |k, v| return v if k == column_name }
|
100
|
-
nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def fk_suffix
|
104
|
-
@opts['foreign_key']['suffix']
|
105
|
-
end
|
106
|
-
|
107
|
-
def to_s
|
108
|
-
@opts.to_s
|
109
|
-
end
|
110
|
-
end
|
111
60
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rare_map/options'
|
2
|
+
|
3
|
+
module RareMap
|
4
|
+
# RareMap::DatabaseProfile defines all metadata of a database.
|
5
|
+
# @author Wei-Ming Wu
|
6
|
+
# @!attribute [r] name
|
7
|
+
# @return [String] the name of this DatabaseProfile
|
8
|
+
# @!attribute [r] connection
|
9
|
+
# @return [Hash] the connection config of this DatabaseProfile
|
10
|
+
# @!attribute [r] options
|
11
|
+
# @return [Options] the Options of this DatabaseProfile
|
12
|
+
# @!attribute schema
|
13
|
+
# @return [String] the schema dump of this DatabaseProfile
|
14
|
+
# @!attribute tables
|
15
|
+
# @return [Array] an Array of Table of this DatabaseProfile
|
16
|
+
class DatabaseProfile
|
17
|
+
attr_reader :name, :connection, :options
|
18
|
+
attr_accessor :schema, :tables
|
19
|
+
|
20
|
+
# Creates a DatabaseProfile.
|
21
|
+
#
|
22
|
+
# @param [String] name the name of this DatabaseProfile
|
23
|
+
# @param [Hash] connection the connection config of this DatabaseProfile
|
24
|
+
# @param [Options] options the Options of this DatabaseProfile
|
25
|
+
# @return [DatabaseProfile] a DatabaseProfile object
|
26
|
+
def initialize(name, connection, options = nil)
|
27
|
+
@name, @connection = name, connection
|
28
|
+
@options = options || Options.new
|
29
|
+
@tables = []
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/rare_map/errors.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
module RareMap
|
2
|
-
|
2
|
+
# RareMap::Errors defines all kinds of errors of RareMap.
|
3
|
+
# @author Wei-Ming Wu
|
4
|
+
module Errors
|
5
|
+
# ConfigNotFoundError is an Exception.
|
6
|
+
class ConfigNotFoundError < Exception ; end
|
7
|
+
# RelationNotDefinedError is an Exception.
|
8
|
+
class RelationNotDefinedError < Exception ; end
|
3
9
|
end
|
4
10
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
|
4
|
+
module RareMap
|
5
|
+
# RareMap::Model defines the details of an ActiveRecord model.
|
6
|
+
# @author Wei-Ming Wu
|
7
|
+
# @!attribute [r] db_name
|
8
|
+
# @return [String] the name of the database
|
9
|
+
# @!attribute [r] connection
|
10
|
+
# @return [Hash] the connection config of this Model
|
11
|
+
# @!attribute [r] table
|
12
|
+
# @return [Table] the Table of this Model
|
13
|
+
# @!attribute [r] group
|
14
|
+
# @return [String] the group of this Model
|
15
|
+
# @!attribute relations
|
16
|
+
# @return [Array] an Array of Relation of this Model
|
17
|
+
class Model
|
18
|
+
include Errors
|
19
|
+
attr_reader :db_name, :connection, :table, :group
|
20
|
+
attr_accessor :relations
|
21
|
+
|
22
|
+
# Creates a Model.
|
23
|
+
#
|
24
|
+
# @param db_name [String] the name of database
|
25
|
+
# @param connection [Hash] the connection config of ActiveRecord
|
26
|
+
# @param table [Table] the database table
|
27
|
+
# @param group [String] the group name of this Model
|
28
|
+
# @return [Model] a Model object
|
29
|
+
def initialize(db_name, connection, table, group = 'default')
|
30
|
+
@db_name, @connection, @table, @group = db_name, connection, table, group
|
31
|
+
@relations = []
|
32
|
+
end
|
33
|
+
|
34
|
+
# Checks if this Model belongs to a group.
|
35
|
+
#
|
36
|
+
# @return [true, false] true if this Model contains a group, false otherwise
|
37
|
+
def group?
|
38
|
+
group != 'default'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the class name of this Model.
|
42
|
+
#
|
43
|
+
# @return [String] the class name of this Model
|
44
|
+
def classify
|
45
|
+
"#{table.name}".pluralize.classify
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,7 +1,14 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
|
+
require 'rare_map/model'
|
3
|
+
require 'rare_map/relation'
|
2
4
|
|
3
5
|
module RareMap
|
6
|
+
# RareMap::ModelBuilder converts an Array of DatabaseProfile into an Array of Model.
|
7
|
+
# @author Wei-Ming Wu
|
4
8
|
module ModelBuilder
|
9
|
+
# Creaetes an Array of Model by given DatabaseProfile(s).
|
10
|
+
#
|
11
|
+
# @return [Array] an Array of Model
|
5
12
|
def build_models(db_profiles)
|
6
13
|
models = []
|
7
14
|
|
@@ -12,9 +19,9 @@ module RareMap
|
|
12
19
|
set_foreign_keys_by_options(table, opts)
|
13
20
|
set_fk_suffix_by_options(table, opts)
|
14
21
|
if opts.group?
|
15
|
-
models << Model.new(db_prof.connection, table, opts.group
|
22
|
+
models << Model.new(db_prof.name, db_prof.connection, table, opts.group)
|
16
23
|
else
|
17
|
-
models << Model.new(db_prof.connection, table
|
24
|
+
models << Model.new(db_prof.name, db_prof.connection, table)
|
18
25
|
end
|
19
26
|
end
|
20
27
|
end
|
@@ -25,6 +32,7 @@ module RareMap
|
|
25
32
|
end
|
26
33
|
|
27
34
|
private
|
35
|
+
|
28
36
|
def build_relations(models)
|
29
37
|
models.each do |model|
|
30
38
|
if model.group?
|
@@ -87,7 +95,7 @@ module RareMap
|
|
87
95
|
def set_foreign_keys_by_options(table, options)
|
88
96
|
table.columns.each do |col|
|
89
97
|
ref = options.find_table_by_foreign_key col.name
|
90
|
-
col.
|
98
|
+
col.ref_table = ref if ref
|
91
99
|
end
|
92
100
|
end
|
93
101
|
|
@@ -96,29 +104,4 @@ module RareMap
|
|
96
104
|
table.primary_key = pk if pk
|
97
105
|
end
|
98
106
|
end
|
99
|
-
|
100
|
-
class Model
|
101
|
-
attr_reader :connection, :table, :group, :relations, :db_name
|
102
|
-
|
103
|
-
def initialize(connection, table, group = 'default', db_name)
|
104
|
-
@connection, @table, @group, @db_name = connection, table, group, db_name
|
105
|
-
@relations = []
|
106
|
-
end
|
107
|
-
|
108
|
-
def group?
|
109
|
-
group != 'default'
|
110
|
-
end
|
111
|
-
|
112
|
-
def classify
|
113
|
-
"#{table.name}".pluralize.classify
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
class Relation
|
118
|
-
attr_reader :type, :foreign_key, :table, :through
|
119
|
-
|
120
|
-
def initialize(type, foreign_key, table, through = nil)
|
121
|
-
@type, @foreign_key, @table, @through = type, foreign_key, table, through
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
107
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'active_support/inflector'
|
2
2
|
|
3
3
|
module RareMap
|
4
|
+
# RareMap::ModelGenerator converts an Array of Model into ActiveRecord files.
|
5
|
+
# @author Wei-Ming Wu
|
4
6
|
module ModelGenerator
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
# Creaetes ActiveRecord files by given Model(s) under app/models directory.
|
8
|
+
def generate_models(models, root = '.')
|
9
|
+
root ||= '.'
|
10
|
+
path = File.join(root, 'app', 'models')
|
11
|
+
Dir.mkdir File.join(root, 'app') unless Dir.exist? File.join(root, 'app')
|
9
12
|
Dir.mkdir path unless Dir.exist? path
|
10
13
|
|
11
14
|
group_db2conn = generate_connection_models(models, path)
|
@@ -53,8 +56,8 @@ module RareMap
|
|
53
56
|
output << " end\n"
|
54
57
|
output << 'end'
|
55
58
|
|
56
|
-
Dir.mkdir path
|
57
|
-
f = File.new(path
|
59
|
+
Dir.mkdir File.join(path, "#{model.group.underscore}") unless Dir.exist? File.join(path, "#{model.group}")
|
60
|
+
f = File.new File.join(path, "#{model.group.underscore}", "#{model.classify.underscore}.rb"), 'w'
|
58
61
|
f.write output
|
59
62
|
f.close
|
60
63
|
end
|
@@ -63,6 +66,7 @@ module RareMap
|
|
63
66
|
end
|
64
67
|
|
65
68
|
private
|
69
|
+
|
66
70
|
def classify_by_table(table, model, models)
|
67
71
|
if model.group?
|
68
72
|
model = models.find { |m| m.table.name == table &&
|
@@ -93,8 +97,8 @@ module RareMap
|
|
93
97
|
'end'
|
94
98
|
|
95
99
|
|
96
|
-
Dir.mkdir path
|
97
|
-
f = File.new(path
|
100
|
+
Dir.mkdir File.join(path, "#{group.underscore}") unless Dir.exist? File.join(path, "#{group}")
|
101
|
+
f = File.new File.join(path, "#{group.underscore}", "#{model.underscore}.rb"), 'w'
|
98
102
|
f.write output
|
99
103
|
f.close
|
100
104
|
|