dm-reflection 0.10.2 → 0.11.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.
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