rare_map 2.1.1 → 2.2.0
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 +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
|
|