momomoto 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/momomoto/base.rb CHANGED
@@ -126,29 +126,41 @@ module Momomoto
126
126
  end
127
127
 
128
128
  # construct the Row class for the table
129
- def initialize_row( row, table )
129
+ def initialize_row( row, table, columns = table.columns )
130
130
 
131
131
  const_set( :Methods, Module.new ) if not const_defined?( :Methods )
132
- const_set( :StandardMethods, Module.new ) if not const_defined?( :StandardMethods )
132
+ row.const_set( :StandardMethods, Module.new ) if not row.const_defined?( :StandardMethods )
133
133
 
134
134
  if not row.ancestors.member?( Momomoto::Row )
135
135
  raise CriticalError, "Row is not inherited from Momomoto::Row"
136
136
  end
137
137
 
138
138
  row.instance_eval do instance_variable_set( :@table, table ) end
139
+ row.instance_eval do instance_variable_set( :@columns, columns ) end
140
+ row.instance_eval do instance_variable_set( :@column_order, columns.keys ) end
139
141
 
140
- define_row_accessors( const_get( :StandardMethods ), table )
142
+ define_row_accessors( row.const_get( :StandardMethods ), table, columns )
141
143
 
142
144
  row.instance_eval do
143
- include table.const_get( :StandardMethods )
145
+ include row.const_get( :StandardMethods )
144
146
  include table.const_get( :Methods )
145
147
  end
146
148
 
149
+ if table.columns.keys.length != columns.keys.length
150
+ unused = table.columns.keys - columns.keys
151
+ unused.each do | field |
152
+ row.class_eval do
153
+ undef_method field if row.instance_methods.member?( "#{field}" )
154
+ undef_method "#{field}=" if row.instance_methods.member?( "#{field}=" )
155
+ end
156
+ end
157
+ end
158
+
147
159
  end
148
160
 
149
161
  # defines row setter and getter in the module StandardMethods which
150
162
  # is later included in the Row class
151
- def define_row_accessors( method_module, table, columns = self.columns )
163
+ def define_row_accessors( method_module, table, columns )
152
164
  columns.each_with_index do | ( field_name, data_type ), index |
153
165
  method_module.instance_eval do
154
166
  # define getter for row class
data/lib/momomoto/row.rb CHANGED
@@ -10,6 +10,14 @@ module Momomoto
10
10
  @table
11
11
  end
12
12
 
13
+ def self.columns
14
+ @columns
15
+ end
16
+
17
+ def self.column_order
18
+ @column_order
19
+ end
20
+
13
21
  def []( fieldname )
14
22
  get_column( fieldname )
15
23
  end
@@ -66,7 +74,7 @@ module Momomoto
66
74
  # convert row to hash
67
75
  def to_hash
68
76
  hash = {}
69
- self.class.table.columns.keys.each do | key |
77
+ self.class.columns.keys.each do | key |
70
78
  hash[key] = self[key]
71
79
  end
72
80
  hash
@@ -79,7 +87,7 @@ module Momomoto
79
87
  raise Error, "Setting primary keys(#{column}) is only allowed for new records"
80
88
  end
81
89
  value = table.columns[column.to_sym].filter_set( value )
82
- index = table.column_order.index( column.to_sym )
90
+ index = self.class.column_order.index( column.to_sym )
83
91
  if !table.columns[column.to_sym].equal( value, @data[index] )
84
92
  mark_dirty( column )
85
93
  @data[index] = value
@@ -89,7 +97,7 @@ module Momomoto
89
97
  # generic getter for column values
90
98
  def get_column( column )
91
99
  table = self.class.table
92
- index = table.column_order.index( column.to_sym )
100
+ index = self.class.column_order.index( column.to_sym )
93
101
  if table.columns[column.to_sym].respond_to?( :filter_get )
94
102
  table.columns[column.to_sym].filter_get( @data[index] )
95
103
  else
@@ -23,7 +23,6 @@ module Momomoto
23
23
  # we store the order separate because it's quite important
24
24
  # that it's constant otherwise get_column and set_column
25
25
  # on the row class might stop working
26
- @column_order = columns.keys
27
26
  @columns = columns
28
27
  end
29
28
 
@@ -36,11 +35,6 @@ module Momomoto
36
35
  @columns
37
36
  end
38
37
 
39
- # get the columns of this table
40
- def column_order #:nodoc:
41
- @column_order
42
- end
43
-
44
38
  def initialize_table # :nodoc:
45
39
 
46
40
  @table_name ||= construct_table_name( self.name )
@@ -57,6 +51,7 @@ module Momomoto
57
51
 
58
52
  const_set( :Row, Class.new( Momomoto::Row ) ) if not const_defined?( :Row )
59
53
  initialize_row( const_get( :Row ), self )
54
+ @row_cache = {}
60
55
 
61
56
  # mark class as initialized
62
57
  self.initialized = true
@@ -118,16 +113,7 @@ module Momomoto
118
113
  # Searches for records and returns an array containing the records
119
114
  def select( conditions = {}, options = {} )
120
115
  initialize_table unless initialized
121
- if options[:columns]
122
- row_class = Class.new( Momomoto::Row )
123
- cols = {}
124
- columns.each do | key, value |
125
- cols[key] = value if options[:columns].member?( key )
126
- end
127
- define_row_accessors( row_class, self, cols )
128
- else
129
- row_class = const_get(:Row)
130
- end
116
+ row_class = build_row_class( options )
131
117
  sql = compile_select( conditions, options )
132
118
  data = []
133
119
  database.execute( sql ).each do | row |
@@ -136,6 +122,25 @@ module Momomoto
136
122
  data
137
123
  end
138
124
 
125
+ def build_row_class( options )
126
+ if options[:columns]
127
+ options[:columns] += primary_keys
128
+ options[:columns].uniq!
129
+ if not @row_cache[options[:columns]]
130
+ row_class = Class.new( Momomoto::Row )
131
+ cols = {}
132
+ columns.each do | key, value |
133
+ cols[key] = value if options[:columns].member?( key )
134
+ end
135
+ initialize_row( row_class, self, cols )
136
+ @row_cache[options[:columns]] = row_class
137
+ end
138
+ return @row_cache[options[:columns]]
139
+ else
140
+ return const_get(:Row)
141
+ end
142
+ end
143
+
139
144
  # Searches for records and returns an array containing the records
140
145
  def select_outer_join( conditions = {}, options = {} )
141
146
  initialize_table unless initialized
@@ -236,7 +241,6 @@ module Momomoto
236
241
 
237
242
  # write row back to database
238
243
  def write( row ) # :nodoc:
239
- raise CriticalError unless row.class == const_get(:Row)
240
244
  if row.new_record?
241
245
  insert( row )
242
246
  else
@@ -274,7 +278,7 @@ module Momomoto
274
278
  def update( row ) # :nodoc:
275
279
  raise CriticalError, 'Updating is only allowed for tables with primary keys' if primary_keys.empty?
276
280
  setter, conditions = [], {}
277
- columns.each do | field_name, data_type |
281
+ row.class.columns.each do | field_name, data_type |
278
282
  next if not row.dirty.member?( field_name )
279
283
  setter << field_name.to_s + ' = ' + data_type.escape(row.get_column(field_name))
280
284
  end
@@ -1,22 +1,18 @@
1
1
 
2
2
  class TestDatatype < Test::Unit::TestCase
3
3
 
4
- DATATYPES = Momomoto::Datatype.constants.map do | t |
5
- Momomoto::Datatype.const_get( t )
6
- end
4
+ Momomoto::Datatype.constants.each do | type_name |
5
+ type = Momomoto::Datatype.const_get( type_name )
7
6
 
8
- def test_default
9
- DATATYPES.each do | type |
7
+ define_method( "test_default_#{type_name}" ) do
10
8
  row = Momomoto::Information_schema::Columns.new
11
9
  row.column_default = 'default-value'
12
10
  a = type.new( row )
13
11
  assert_equal( 'default-value', a.default )
14
12
  assert_equal( false, type.new.default )
15
13
  end
16
- end
17
14
 
18
- def test_not_null
19
- DATATYPES.each do | type |
15
+ define_method( "test_not_null_#{type_name}" ) do
20
16
  row = Momomoto::Information_schema::Columns.new
21
17
  row.is_nullable = "YES"
22
18
  assert_equal( false, type.new( row ).not_null? )
@@ -25,10 +21,8 @@ class TestDatatype < Test::Unit::TestCase
25
21
  row.is_nullable = nil
26
22
  assert_equal( false, type.new( row ).not_null? )
27
23
  end
28
- end
29
24
 
30
- def test_compile_rule
31
- DATATYPES.each do | type |
25
+ define_method( "test_compile_rule_#{type_name}" ) do
32
26
  t = type.new
33
27
  tests = [ nil, [], [nil], [nil,nil], {}, {:eq=>nil}, {nil=>nil}]
34
28
  tests.each do | test |
@@ -37,18 +31,14 @@ class TestDatatype < Test::Unit::TestCase
37
31
  end
38
32
  end
39
33
  end
40
- end
41
34
 
42
- def test_compile_rule_null
43
- DATATYPES.each do | type |
35
+ define_method( "test_compile_rule_null_#{type_name}" ) do
44
36
  t = type.new
45
37
  assert_equal( "field_name IS NULL", t.compile_rule( :field_name, :NULL) )
46
38
  assert_equal( "field_name IS NOT NULL", t.compile_rule( :field_name, :NOT_NULL) )
47
39
  end
48
- end
49
40
 
50
- def test_operator_sign
51
- DATATYPES.each do | type |
41
+ define_method( "test_operator_sign_#{type_name}" ) do
52
42
  assert_equal( '<=', type.operator_sign( :le ) )
53
43
  assert_equal( '<', type.operator_sign( :lt ) )
54
44
  assert_equal( '>=', type.operator_sign( :ge ) )
@@ -57,10 +47,8 @@ class TestDatatype < Test::Unit::TestCase
57
47
  assert_equal( '<>', type.operator_sign( :ne ) )
58
48
  assert_raise( Momomoto::CriticalError ) { type.operator_sign( :foo ) }
59
49
  end
60
- end
61
50
 
62
- def test_escape
63
- DATATYPES.each do | type |
51
+ define_method( "test_escape_#{type_name}" ) do
64
52
  t = type.new
65
53
  assert_equal( 'NULL', t.escape( nil ))
66
54
  end
data/test/test_row.rb CHANGED
@@ -56,6 +56,12 @@ class TestRow < Test::Unit::TestCase
56
56
  assert( b == a )
57
57
  end
58
58
 
59
+ def test_columns
60
+ a = Person.new
61
+ assert_equal( Person.columns, a.class.columns )
62
+ assert_equal( Person.columns, Person::Row.columns )
63
+ end
64
+
59
65
  def test_primary_key_setting
60
66
  a = Person.select_single( nil, {:limit=>1})
61
67
  assert_raise( Momomoto::Error ) do
data/test/test_table.rb CHANGED
@@ -132,14 +132,28 @@ class TestTable < Test::Unit::TestCase
132
132
  end
133
133
 
134
134
  def test_select_columns
135
- p = Person.select({},{:columns=>[:person_id,:first_name],:limit=>1})[0]
135
+ p = Person.select({},{:columns=>[:first_name,:nick_name],:limit=>1})[0]
136
136
  assert( p.respond_to?( :person_id ))
137
137
  assert( p.respond_to?( :first_name ))
138
+ assert( p.respond_to?( :nick_name ))
139
+ p.first_name = 'bacon'
140
+ p.nick_name = 'abc'
141
+ assert_equal( p.first_name + 'abc', p.nick_name )
138
142
  assert_raise( NoMethodError ) do
139
- p.nick_name
143
+ p.last_name
140
144
  end
141
145
  end
142
146
 
147
+ def test_write_columns
148
+ p = Person.select({},{:columns=>[:first_name],:limit=>1})[0]
149
+ p.first_name = 'test_write_columns'
150
+ p.write
151
+ p2 = Person.select_single(:person_id=>p.person_id)
152
+ assert_equal( 'test_write_columns', p2.first_name )
153
+ p2.first_name = 'chunky'
154
+ p2.write
155
+ end
156
+
143
157
  def test_select
144
158
  r = Person.select( nil, {:limit => 3})
145
159
  assert_equal( 3, r.length )
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: momomoto
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.7
7
- date: 2007-10-07 00:00:00 +02:00
6
+ version: 0.1.8
7
+ date: 2007-10-15 00:00:00 +02:00
8
8
  summary: Momomoto is an object relational mapper for PostgreSQL.
9
9
  require_paths:
10
10
  - lib