dm-reflection 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +0 -1
- data/VERSION +1 -1
- data/dm-reflection.gemspec +2 -2
- data/lib/dm-reflection/adapters/mysql.rb +47 -8
- data/lib/dm-reflection/adapters/persevere.rb +33 -24
- data/lib/dm-reflection/adapters/postgres.rb +4 -0
- data/lib/dm-reflection/adapters/sqlite3.rb +4 -0
- data/lib/dm-reflection/reflection.rb +25 -8
- data/spec/persevere_reflection_spec.rb +0 -10
- metadata +4 -4
data/.gitignore
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
data/dm-reflection.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{dm-reflection}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.11.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Martin Gamsjaeger (snusnu), Yogo Team"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-06-09}
|
13
13
|
s.description = %q{Generates datamapper models from existing database schemas and export them to files}
|
14
14
|
s.email = %q{irjudson [a] gmail [d] com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -44,6 +44,10 @@ module DataMapper
|
|
44
44
|
}[$1] || raise("unknown type: #{db_type}")
|
45
45
|
end
|
46
46
|
|
47
|
+
def separator
|
48
|
+
'--'
|
49
|
+
end
|
50
|
+
|
47
51
|
##
|
48
52
|
# Get the list of table names
|
49
53
|
#
|
@@ -54,6 +58,23 @@ module DataMapper
|
|
54
58
|
select("SHOW FULL TABLES FROM #{options[:path][1..-1]} WHERE Table_type = 'BASE TABLE'").map { |item| item.first }
|
55
59
|
end
|
56
60
|
|
61
|
+
##
|
62
|
+
# This method breaks the join table into the two other table names
|
63
|
+
#
|
64
|
+
# @param [String] Name join table name
|
65
|
+
# @return [String,String] The two other table names joined.
|
66
|
+
#
|
67
|
+
def join_table_name(name, name_list=nil)
|
68
|
+
name_list = get_storage_names.sort if name_list.nil?
|
69
|
+
left = name_list[name_list.index(name)-1]
|
70
|
+
right = name[left.length+1..-1]
|
71
|
+
if name_list.include?(right)
|
72
|
+
return left,right
|
73
|
+
else
|
74
|
+
return nil,nil
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
57
78
|
##
|
58
79
|
# Get the column specifications for a specific table
|
59
80
|
#
|
@@ -65,8 +86,15 @@ module DataMapper
|
|
65
86
|
#
|
66
87
|
def get_properties(table)
|
67
88
|
# TODO: use SHOW INDEXES to find out unique and non-unique indexes
|
89
|
+
join_table = false
|
90
|
+
columns = select("SHOW COLUMNS FROM #{table} IN #{options[:path][1..-1]};")
|
68
91
|
|
69
|
-
|
92
|
+
if columns.length == 2 && columns[0].field.downcase[-3,3] == "_id" && columns[1].field.downcase[-3,3] == "_id"
|
93
|
+
left_table_name,right_table_name = join_table_name(table)
|
94
|
+
join_table = true
|
95
|
+
end
|
96
|
+
|
97
|
+
columns.map do |column|
|
70
98
|
type = get_type(column.type)
|
71
99
|
auto_increment = column.extra == 'auto_increment'
|
72
100
|
|
@@ -84,24 +112,35 @@ module DataMapper
|
|
84
112
|
:key => column.key == 'PRI',
|
85
113
|
}
|
86
114
|
|
87
|
-
|
115
|
+
# TODO: use the naming convention to compare the name vs the column name
|
116
|
+
unless attribute[:name] == column.field
|
117
|
+
attribute[:field] = column.field
|
118
|
+
end
|
119
|
+
|
120
|
+
if join_table
|
121
|
+
attribute[:type] = DataMapper::Associations::Relationship
|
122
|
+
attribute[:relationship] = {
|
123
|
+
# M:M requires we wire things a bit differently and remove the join model
|
124
|
+
:many_to_many => true,
|
125
|
+
:parent => Extlib::Inflection.classify(left_table_name),
|
126
|
+
:child => Extlib::Inflection.classify(right_table_name),
|
127
|
+
# When we can detect more from the database we can optimize this
|
128
|
+
:cardinality => Infinity,
|
129
|
+
:bidirectional => true }
|
130
|
+
return [attribute]
|
131
|
+
elsif type == Integer && field_name[-3,3] == "_id"
|
88
132
|
# This is a foriegn key. So this model belongs_to the other (_id) one.
|
89
133
|
# Add a special set of values and flag this as a relationship so the reflection code
|
90
134
|
# can rebuild the relationship when it's building the model.
|
91
135
|
attribute[:type] = DataMapper::Associations::Relationship
|
92
136
|
attribute[:relationship] = {
|
137
|
+
:many_to_many => false,
|
93
138
|
:parent => Extlib::Inflection.classify(field_name[0..-4]),
|
94
139
|
:child => Extlib::Inflection.classify(table),
|
95
140
|
# When we can detect more from the database we can optimize this
|
96
141
|
:cardinality => Infinity,
|
97
142
|
:bidirectional => true }
|
98
143
|
end
|
99
|
-
|
100
|
-
# TODO: use the naming convention to compare the name vs the column name
|
101
|
-
unless attribute[:name] == column.field
|
102
|
-
attribute[:field] = column.field
|
103
|
-
end
|
104
|
-
|
105
144
|
attribute
|
106
145
|
end
|
107
146
|
end
|
@@ -15,12 +15,14 @@ module DataMapper
|
|
15
15
|
#
|
16
16
|
chainable do
|
17
17
|
def get_type(db_type)
|
18
|
+
|
19
|
+
return :has_one_relation if db_type.has_key?("$ref")
|
20
|
+
|
18
21
|
type = db_type['type']
|
19
22
|
format = db_type['format']
|
20
23
|
|
21
24
|
case type
|
22
|
-
when
|
23
|
-
when 'array' then DataMapper::Types::JsonReferenceCollection
|
25
|
+
when 'array' then :has_many_relation
|
24
26
|
when 'serial' then DataMapper::Types::Serial
|
25
27
|
when 'integer' then Integer
|
26
28
|
# when 'number' then BigDecimal
|
@@ -36,6 +38,11 @@ module DataMapper
|
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
41
|
+
|
42
|
+
def separator
|
43
|
+
'/'
|
44
|
+
end
|
45
|
+
|
39
46
|
##
|
40
47
|
# Get the list of schema names
|
41
48
|
#
|
@@ -43,7 +50,7 @@ module DataMapper
|
|
43
50
|
#
|
44
51
|
def get_storage_names
|
45
52
|
@schemas = self.get_schema
|
46
|
-
@schemas.map { |schema| schema['id']
|
53
|
+
@schemas.map { |schema| schema['id'] }
|
47
54
|
end
|
48
55
|
|
49
56
|
##
|
@@ -57,32 +64,34 @@ module DataMapper
|
|
57
64
|
#
|
58
65
|
chainable do
|
59
66
|
def get_properties(table)
|
60
|
-
|
61
|
-
schema = self.get_schema(table
|
67
|
+
attributes = Array.new
|
68
|
+
schema = self.get_schema(table)[0]
|
62
69
|
schema['properties'].each_pair do |key, value|
|
63
70
|
type = get_type(value)
|
64
|
-
property = {:name => key, :type => type }
|
65
|
-
property.merge!({ :required => !value.delete('optional'),
|
66
|
-
:key => value.has_key?('index') && value.delete('index') }) unless property[:type] == DataMapper::Types::Serial
|
67
|
-
|
68
|
-
if type.kind_of?(DataMapper::Types::JsonReference)
|
69
|
-
property.merge!( {:reference => derive_relationship_model(value[:type]["$ref"])} )
|
70
|
-
end
|
71
71
|
|
72
|
-
|
73
|
-
property.merge!( {:reference => derive_relationship_model(value[:items]["$ref"])} )
|
74
|
-
end
|
72
|
+
attribute = { :name => key }
|
75
73
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
74
|
+
if type == :has_one_relation
|
75
|
+
# Has one
|
76
|
+
# Retrieve the other side to determine the cardinality
|
77
|
+
other_table = [table.split('/')[0..-2], value['$ref']].join("/")
|
78
|
+
other_schema = self.get_schema(other_table)[0]
|
79
|
+
|
80
|
+
elsif type == :has_many_relation
|
81
|
+
# Has many
|
82
|
+
# Retrieve the other side to determine the cardinality
|
83
|
+
other_table = [table.split('/')[0..-2], value['items']['$ref']].join("/")
|
84
|
+
other_schema = self.get_schema(other_table)[0]
|
85
|
+
|
86
|
+
else
|
87
|
+
attribute.merge!({ :type => type, :required => !value.delete('optional'), :key => value.has_key?('index') && value.delete('index') }) unless attribute[:type] == DataMapper::Types::Serial
|
88
|
+
['type', 'format', 'unique', 'index', 'items'].each { |key| value.delete(key) }
|
89
|
+
value.keys.each { |key| value[key.to_sym] = value[key]; value.delete(key) }
|
90
|
+
attribute.merge!(value)
|
91
|
+
attributes << attribute
|
92
|
+
end
|
84
93
|
end
|
85
|
-
return
|
94
|
+
return attributes
|
86
95
|
end
|
87
96
|
end
|
88
97
|
|
@@ -9,11 +9,11 @@ module DataMapper
|
|
9
9
|
#
|
10
10
|
def self.reflect(repository, namespace = Object, overwrite = false)
|
11
11
|
adapter = DataMapper.repository(repository).adapter
|
12
|
-
|
12
|
+
separator = adapter.separator
|
13
13
|
models = Hash.new
|
14
14
|
|
15
15
|
adapter.get_storage_names.each do |storage_name|
|
16
|
-
namespace_parts = storage_name.split(
|
16
|
+
namespace_parts = storage_name.split(separator).map do |part|
|
17
17
|
Extlib::Inflection.classify(part)
|
18
18
|
end
|
19
19
|
|
@@ -43,14 +43,26 @@ module DataMapper
|
|
43
43
|
models[model_name] = namespace.const_set(model_name, anonymous_model)
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
join_models = Array.new
|
47
|
+
|
48
|
+
models.each do |model_name, model|
|
47
49
|
adapter.get_properties(model.storage_name).each do |attribute|
|
48
50
|
if attribute[:type] == DataMapper::Associations::Relationship
|
49
51
|
parent = models[attribute[:relationship][:parent]]
|
50
52
|
child = models[attribute[:relationship][:child]]
|
51
|
-
|
52
|
-
|
53
|
-
|
53
|
+
if parent.nil? or child.nil?
|
54
|
+
puts "Reflection Relationship: P: #{parent.inspect} C: #{child.inspect} A: #{attribute[:relationship].inspect}"
|
55
|
+
end
|
56
|
+
if attribute[:relationship][:many_to_many]
|
57
|
+
parent.has(attribute[:relationship][:cardinality], child.name.tableize.pluralize.downcase.to_sym, :through => DataMapper::Resource, :model => child)
|
58
|
+
child.has(attribute[:relationship][:cardinality], parent.name.tableize.pluralize.downcase.to_sym, :through => DataMapper::Resource, :model => parent)
|
59
|
+
# Remove join model
|
60
|
+
join_models << model_name
|
61
|
+
else
|
62
|
+
child.belongs_to(parent.name.tableize.downcase.to_sym, :model => parent)
|
63
|
+
if attribute[:relationship][:bidirectional]
|
64
|
+
parent.has(attribute[:relationship][:cardinality], child.name.tableize.pluralize.downcase.to_sym, :model => child)
|
65
|
+
end
|
54
66
|
end
|
55
67
|
else
|
56
68
|
attribute.delete_if { |k,v| v.nil? }
|
@@ -58,8 +70,13 @@ module DataMapper
|
|
58
70
|
end
|
59
71
|
end
|
60
72
|
end
|
61
|
-
|
62
|
-
|
73
|
+
|
74
|
+
join_models.each do |model|
|
75
|
+
models.delete(model)
|
76
|
+
DataMapper::Model.descendants.delete(model)
|
77
|
+
end
|
78
|
+
|
79
|
+
models.values
|
63
80
|
end
|
64
81
|
end # module Reflection
|
65
82
|
|
@@ -28,8 +28,6 @@ if ENV['ADAPTER'] == 'persevere'
|
|
28
28
|
property :body, Text, :length => 65535, :lazy => true
|
29
29
|
property :updated_at, DateTime
|
30
30
|
property :score, Integer
|
31
|
-
property :blog_post, DataMapper::Types::JsonReference, :reference => :Post
|
32
|
-
|
33
31
|
|
34
32
|
end
|
35
33
|
RUBY
|
@@ -49,8 +47,6 @@ if ENV['ADAPTER'] == 'persevere'
|
|
49
47
|
}
|
50
48
|
|
51
49
|
@models.each_key { |model| Extlib::Inflection.constantize(model.to_s).auto_migrate! }
|
52
|
-
Post.send(:property, :comments, DataMapper::Types::JsonReferenceCollection, :reference => :PostComment)
|
53
|
-
Post.auto_upgrade!
|
54
50
|
@models.each_key { |model| remove_model_from_memory( Extlib::Inflection.constantize(model.to_s) ) }
|
55
51
|
end
|
56
52
|
|
@@ -75,12 +71,6 @@ if ENV['ADAPTER'] == 'persevere'
|
|
75
71
|
result = @adapter.get_properties("post")
|
76
72
|
result.should be_kind_of(Array)
|
77
73
|
end
|
78
|
-
|
79
|
-
it "should reflect out JsonReference types" do
|
80
|
-
DataMapper::Reflection.reflect(:default)
|
81
|
-
PostComment.properties[:blog_post].type.should eql DataMapper::Types::JsonReference
|
82
|
-
Post.properties[:comments].type.should eql DataMapper::Types::JsonReferenceCollection
|
83
|
-
end
|
84
74
|
|
85
75
|
end
|
86
76
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 11
|
8
|
+
- 0
|
9
|
+
version: 0.11.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Martin Gamsjaeger (snusnu), Yogo Team
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-06-09 00:00:00 -06:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|