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 CHANGED
@@ -17,7 +17,6 @@ tmtags
17
17
  coverage
18
18
  rdoc
19
19
  pkg
20
- *.gemspec
21
20
 
22
21
  ## PROJECT::SPECIFIC
23
22
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.2
1
+ 0.11.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dm-reflection}
8
- s.version = "0.10.2"
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-05-05}
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
- select("SHOW COLUMNS FROM #{table} IN #{options[:path][1..-1]};").map do |column|
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
- if type == Integer && field_name[-3,3] == "_id"
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 Hash then DataMapper::Types::JsonReference
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'].gsub('/', '__') }
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
- results = Array.new
61
- schema = self.get_schema(table.gsub('__', '/'))[0]
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
- if type.kind_of?(DataMapper::Types::JsonReferenceCollection)
73
- property.merge!( {:reference => derive_relationship_model(value[:items]["$ref"])} )
74
- end
72
+ attribute = { :name => key }
75
73
 
76
- value.delete('type')
77
- value.delete('format')
78
- value.delete('unique')
79
- value.delete('index')
80
- value.delete('items')
81
- value.keys.each { |key| value[key.to_sym] = value[key]; value.delete(key) }
82
- property.merge!(value)
83
- results << property
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 results
94
+ return attributes
86
95
  end
87
96
  end
88
97
 
@@ -29,6 +29,10 @@ module DataMapper
29
29
  }[db_type] || raise("unknown db type: #{db_type}")
30
30
  end
31
31
 
32
+ def separator
33
+ '--'
34
+ end
35
+
32
36
  ##
33
37
  # Get the list of table names
34
38
  #
@@ -25,6 +25,10 @@ module DataMapper
25
25
  }[$1] || raise("unknown db type: #{db_type}")
26
26
  end
27
27
 
28
+ def separator
29
+ '--'
30
+ end
31
+
28
32
  ##
29
33
  # Get the list of table names
30
34
  #
@@ -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('__').map do |part|
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
- models.values.each do |model|
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
- child.belongs_to(parent.name.downcase.to_sym)
52
- if attribute[:relationship][:bidirectional]
53
- parent.has(attribute[:relationship][:cardinality], child.name.pluralize.downcase.to_sym)
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
- models.to_a
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
- - 10
8
- - 2
9
- version: 0.10.2
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-05-05 00:00:00 -06:00
17
+ date: 2010-06-09 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency