Rubernate 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/db/mysql.sql CHANGED
@@ -20,6 +20,7 @@ CREATE TABLE R_PARAMS (
20
20
  NAME VARCHAR(100) NOT NULL,
21
21
  FLAGS INTEGER(5) NOT NULL,
22
22
  INT_VALUE INTEGER(20),
23
+ FLT_VALUE FLOAT,
23
24
  STR_VALUE VARCHAR(255),
24
25
  DAT_VALUE DATETIME,
25
26
  REF_VALUE INTEGER(20),
data/db/oracle.sql CHANGED
@@ -12,6 +12,7 @@ CREATE TABLE R_PARAMS (
12
12
  NAME VARCHAR2(100) NOT NULL,
13
13
  FLAGS NUMBER(5) NOT NULL,
14
14
  INT_VALUE NUMBER(20),
15
+ FLT_VALUE FLOAT,
15
16
  STR_VALUE VARCHAR2(1000),
16
17
  DAT_VALUE DATE,
17
18
  REF_VALUE NUMBER(20),
@@ -5,7 +5,7 @@ module Rubernate
5
5
  # in other to extend basic functionality.
6
6
  module Callbacks
7
7
  # This module contains callback methods and
8
- # included in module Rubernate::Entity
8
+ # included in all persisten classes.
9
9
  module Entity
10
10
  # Invoked if object has just been created in database.
11
11
  def on_create
@@ -23,7 +23,7 @@ module Callbacks
23
23
  def on_load
24
24
  end
25
25
 
26
- # Invoked if property of object has just been reassigned by +=+ operator.
26
+ # Invoked if property of object has just been changed via = or [] = operator.
27
27
  def on_change prop_name, old_value, new_value
28
28
  end
29
29
 
@@ -6,7 +6,7 @@ module Entity
6
6
  include Callbacks::Entity
7
7
 
8
8
  # This property holds objects primary key.
9
- # The primary key is not +nil+ for objects attached to session.
9
+ # The primary key is not nil for objects attached to session.
10
10
  attr :primary_key, true
11
11
 
12
12
  # Attaches object to session returns self
@@ -26,13 +26,13 @@ module Entity
26
26
  @removed
27
27
  end
28
28
 
29
- # Retruns objects +peer+ if ther is one or +nil+ in other case
29
+ # Retruns objects peer if ther is one or nil in other case
30
30
  def peer
31
31
  @peer
32
32
  end
33
33
 
34
34
  # Sets peer if there is no one and invokes on_load callback else skip.
35
- # If value is _nil_ peer will be lazy initialized in ensure_loaded.
35
+ # If value is nil peer will be lazy initialized in ensure_loaded.
36
36
  # This method should be invoked only once with not nil value.
37
37
  def peer= value
38
38
  return if @peer
@@ -5,23 +5,27 @@ module Rubernate
5
5
  module DBI
6
6
  # Param flags constants
7
7
  PARAM_FLAG_INT = (1 << 0).to_i
8
- PARAM_FLAG_STRING = (1 << 1).to_i
9
- PARAM_FLAG_TIME = (1 << 2).to_i
10
- PARAM_FLAG_DATE = (1 << 3).to_i
11
- PARAM_FLAG_REF = (1 << 4).to_i
12
- PARAM_FLAG_ARRAY = (1 << 5).to_i
13
- PARAM_FLAG_HASH = (1 << 6).to_i
8
+ PARAM_FLAG_FLOAT = (1 << 1).to_i
9
+ PARAM_FLAG_STRING = (1 << 2).to_i
10
+ PARAM_FLAG_TIME = (1 << 3).to_i
11
+ PARAM_FLAG_DATE = (1 << 4).to_i
12
+ PARAM_FLAG_REF = (1 << 5).to_i
13
+ PARAM_FLAG_ARRAY = (1 << 6).to_i
14
+ PARAM_FLAG_HASH = (1 << 7).to_i
14
15
 
15
16
  # Array and Hashs combinations
16
17
  ARRAY_INT_REF = (PARAM_FLAG_ARRAY | PARAM_FLAG_INT).to_i
17
18
  HASH_INT_REF = (PARAM_FLAG_HASH | PARAM_FLAG_INT).to_i
19
+ HASH_FLOAT_REF = (PARAM_FLAG_HASH | PARAM_FLAG_FLOAT).to_i
18
20
  HASH_STRING_REF = (PARAM_FLAG_HASH | PARAM_FLAG_STRING).to_i
19
21
  HASH_TIME_REF = (PARAM_FLAG_HASH | PARAM_FLAG_TIME).to_i
20
22
  HASH_DATE_REF = (PARAM_FLAG_HASH | PARAM_FLAG_DATE).to_i
21
23
 
24
+ TimeType = ::DBI::Timestamp
25
+
22
26
  # Represents factory for +Runtime+ implementors.
23
27
  class RuntimeFactory
24
- # Accepts +Runtime+ impl. class, database url, user name, and user password
28
+ # Accepts Runtime impl. class, database url, user name, and user password
25
29
  def initialize klass, db_url, db_user, db_password
26
30
  @klass, @db_url, @db_user, @db_password = klass, db_url, db_user, db_password
27
31
  # @params = {'AutoCommit' => false} #TODO: refine
@@ -45,11 +49,11 @@ module DBI
45
49
  end
46
50
 
47
51
  # Represent base class for all Runtime implementation.
48
- # Contains generic sql implementations of all required methods except +create+.
49
- # The +create+ method should be implemented in subclasses.
52
+ # Contains generic sql implementations of all required methods except create.
53
+ #Method create should be implemented in subclasses.
50
54
  class Runtime < Rubernate::Runtime
51
55
  include DBI
52
-
56
+
53
57
  # Parameters are deleted automatically with corresponding r_object records
54
58
  #DELETE_PARAMS = <<-SQL
55
59
  # DELETE FROM R_PARAMS WHERE OBJECT_PK = ?
@@ -61,35 +65,34 @@ module DBI
61
65
  DELETE FROM R_OBJECTS WHERE OBJECT_PK = ?
62
66
  SQL
63
67
  SAVE_PARAMS = <<-SQL
64
- INSERT INTO R_PARAMS VALUES (?, ?, ?, ?, ?, ?, ?)
68
+ INSERT INTO R_PARAMS VALUES (?, ?, ?, ?, ?, ?, ?, ?)
65
69
  SQL
66
70
  SELECT_PARAMS = <<-SQL
67
- SELECT P.*, O.OBJECT_CLASS, R.OBJECT_CLASS
71
+ SELECT P.*, R.OBJECT_CLASS, O.OBJECT_CLASS
68
72
  FROM R_PARAMS P JOIN R_OBJECTS O ON (O.OBJECT_PK = P.OBJECT_PK)
69
73
  LEFT OUTER JOIN R_OBJECTS R ON (P.REF_VALUE = R.OBJECT_PK)
70
74
  WHERE O.OBJECT_PK IN
71
75
  SQL
72
76
  SELECT_ONE_OBJECT = <<-SQL
73
- SELECT O.OBJECT_PK, P.NAME, P.FLAGS, P.INT_VALUE, P.STR_VALUE,
74
- P.DAT_VALUE, P.REF_VALUE, O.OBJECT_CLASS, R.OBJECT_CLASS
77
+ SELECT O.OBJECT_PK, P.NAME, P.FLAGS, P.INT_VALUE, P.FLT_VALUE, P.STR_VALUE,
78
+ P.DAT_VALUE, P.REF_VALUE, R.OBJECT_CLASS, O.OBJECT_CLASS
75
79
  FROM R_OBJECTS O
76
80
  LEFT OUTER JOIN R_PARAMS P ON (O.OBJECT_PK = P.OBJECT_PK)
77
81
  LEFT OUTER JOIN R_OBJECTS R ON (P.REF_VALUE = R.OBJECT_PK)
78
82
  WHERE O.OBJECT_PK = ?
79
83
  SQL
80
-
81
- # R_OBJECTS table's column's indexes
82
- CI_O_PK = 0
83
- CI_O_CLASS = 1
84
-
84
+
85
85
  # R_PARAMS table's column's indexes
86
- CI_P_PK = 0
87
- CI_P_NAME = 1
88
- CI_P_FLAGS = 2
89
- CI_P_INT = 3
90
- CI_P_STR = 4
91
- CI_P_TIME = 5
92
- CI_P_REF = 6
86
+ P_PK = 0
87
+ P_NAME = 1
88
+ P_FLAGS = 2
89
+ P_INT = 3
90
+ P_FLT = 4
91
+ P_STR = 5
92
+ P_TIME = 6
93
+ P_REF = 7 # Refered object PK
94
+ P_REF_CLASS = 8 # Refered object Class
95
+ P_CLASS = 9 # Self object Class
93
96
 
94
97
  attr :dbh, false
95
98
 
@@ -121,14 +124,14 @@ module DBI
121
124
  # Loads object by primary_key
122
125
  def load_by_pk pk
123
126
  klass, peer = nil
124
- dbh.execute(SELECT_ONE_OBJECT, pk) { |sth|
125
- sth.fetch { |row|
126
- klass, peer = row[7], Rubernate::Peer.new unless klass
127
+ dbh.execute SELECT_ONE_OBJECT, pk do |sth|
128
+ sth.fetch do |row|
129
+ klass, peer = row[P_CLASS], Rubernate::Peer.new unless klass
127
130
  fetch_param peer, row
128
- }
129
- }
131
+ end
132
+ end
130
133
  return nil unless klass
131
- obj = instantiate pk, class_by_name(klass), peer
134
+ obj = instantiate pk, klass, peer
132
135
  post_load obj
133
136
  obj
134
137
  end
@@ -140,7 +143,7 @@ module DBI
140
143
  # selects objects and stores not loaded to buffer
141
144
  dbh.execute(query, *params) { |sth|
142
145
  sth.fetch { |row|
143
- obj = instantiate row[0].to_i, class_by_name(row[1])
146
+ obj = instantiate row[0].to_i, row[1]
144
147
  buffer[obj.primary_key], obj.peer = obj, Rubernate::Peer.new unless obj.peer
145
148
  result << obj
146
149
  }
@@ -148,8 +151,8 @@ module DBI
148
151
  return result if buffer.empty?
149
152
  # load peers for objects in buffer.
150
153
  dbh.execute(SELECT_PARAMS + object_ids_p(buffer.values)) {|sth|
151
- sth.fetch {|row|
152
- fetch_param buffer[row[0].to_i].peer, row
154
+ sth.fetch {|row|
155
+ fetch_param buffer[row[P_PK].to_i].peer, row
153
156
  }
154
157
  }
155
158
  # clears dirty flags
@@ -182,70 +185,72 @@ module DBI
182
185
  when Hash: save_hash sth, pk, name, param
183
186
  when Array: save_array sth, pk, name, param
184
187
  when Integer: save_int sth, pk, name, param
188
+ when Float: save_float sth, pk, name, param
185
189
  when Time: save_time sth, pk, name, param
186
190
  when Date: save_date sth, pk, name, param
187
- else save_str sth, pk, name, param
191
+ else save_str sth, pk, name, param.to_s
188
192
  end
189
193
  end
190
-
191
- def save_ref sth, pk, name, ref
192
- sth.execute pk, name, PARAM_FLAG_REF, nil, nil, nil, ref.primary_key unless ref.removed?
194
+
195
+ def save_int sth, pk, name, int
196
+ sth.execute pk, name, PARAM_FLAG_INT, int, nil, nil, nil, nil
193
197
  end
198
+
199
+ def save_float sth, pk, name, float
200
+ sth.execute pk, name, PARAM_FLAG_FLOAT, nil, float, nil, nil, nil
201
+ end
202
+
203
+ def save_str sth, pk, name, str
204
+ sth.execute pk, name, PARAM_FLAG_STRING, nil, nil, str, nil, nil
205
+ end
194
206
 
195
207
  def save_time sth, pk, name, time
196
- sth.execute pk, name, PARAM_FLAG_TIME, nil, nil, ::DBI::Timestamp.new(time), nil
208
+ sth.execute pk, name, PARAM_FLAG_TIME, nil, nil, nil, TimeType.new(time), nil
197
209
  end
198
210
 
199
211
  def save_date sth, pk, name, date
200
- sth.execute pk, name, PARAM_FLAG_DATE, nil, nil, ::DBI::Timestamp.new(date), nil
212
+ sth.execute pk, name, PARAM_FLAG_DATE, nil, nil, nil, TimeType.new(date), nil
201
213
  end
214
+
215
+ def save_ref sth, pk, name, ref
216
+ sth.execute pk, name, PARAM_FLAG_REF, nil, nil, nil, nil, ref.primary_key unless ref.removed?
217
+ end
202
218
 
203
219
  def save_hash sth, pk, name, hash
204
- hash.delete_if {|key, ref| ref.removed?}
220
+ hash.delete_if {|key, ref| ref.removed?} # Discard removed objects
205
221
  if hash.empty?
206
- sth.execute pk, name, PARAM_FLAG_HASH, 0, nil, nil, nil
222
+ sth.execute pk, name, PARAM_FLAG_HASH, 0, nil, nil, nil, nil
207
223
  else
208
224
  hash.each {|key, ref| save_key_value sth, pk, name, key, ref.primary_key}
209
225
  end
210
226
  end
211
227
 
212
228
  def save_key_value sth, pk, name, key, ref
213
- if key.is_a? String
214
- sth.execute pk, name, HASH_STRING_REF, nil, key, nil, ref
215
- elsif key.is_a? Integer
216
- sth.execute pk, name, HASH_INT_REF, key, nil, nil, ref
217
- elsif key.is_a? ::Time # TODO: chek time and date scopes?
218
- sth.execute pk, name, HASH_TIME_REF, nil, nil, ::DBI::Timestamp.new(key), ref
219
- elsif key.is_a? ::Date
220
- sth.execute pk, name, HASH_DATE_REF, nil, nil, ::DBI::Timestamp.new(key), ref
221
- elsif key.nil?
222
- sth.execute pk, name, PARAM_FLAG_HASH, nil, nil, nil, ref
223
- else
224
- raise "invalid hash key value #{key}"
229
+ case key
230
+ when Integer: sth.execute pk, name, HASH_INT_REF, key, nil, nil, nil, ref
231
+ when Float: sth.execute pk, name, HASH_FLOAT_REF, nil, key, nil, nil, ref
232
+ when String: sth.execute pk, name, HASH_STRING_REF, nil, nil, key, nil, ref
233
+ when ::Date: sth.execute pk, name, HASH_DATE_REF, nil, nil, nil, TimeType.new(key), ref
234
+ when ::Time: sth.execute pk, name, HASH_TIME_REF, nil, nil, nil, TimeType.new(key), ref
235
+ when nil: sth.execute pk, name, PARAM_FLAG_HASH, nil, nil, nil, nil, ref
236
+ else
237
+ raise "invalid hash key value #{key}"
225
238
  end
226
239
  end
227
240
 
228
241
  def save_array sth, pk, name, array
229
- array.delete_if {|ref| !ref or ref.removed?} # Reject removed and nil items
242
+ array.delete_if {|ref| !ref or ref.removed?} # Discard removed and nil items
230
243
  if array.empty? # Empty arrays should also be stored
231
- sth.execute pk, name, ARRAY_INT_REF, 0, nil, nil, nil
244
+ sth.execute pk, name, ARRAY_INT_REF, 0, nil, nil, nil, nil
232
245
  else
233
- array.each_index { |idx| sth.execute pk, name,
234
- ARRAY_INT_REF, idx, nil, nil, array[idx].primary_key}
246
+ array.each_index {|idx| sth.execute pk, name,
247
+ ARRAY_INT_REF, idx, nil, nil, nil, array[idx].primary_key}
235
248
  end
236
249
  end
237
250
 
238
- def save_int sth, pk, name, param
239
- sth.execute pk, name, PARAM_FLAG_INT, param, nil, nil, nil
240
- end
241
-
242
- def save_str sth, pk, name, param
243
- sth.execute pk, name, PARAM_FLAG_STRING, nil, param.to_s, nil, nil
244
- end
245
-
246
251
  def fetch_param peer, row
247
- return unless row[1] # there are no params for this object
248
- name, flags, ref = row[1].to_sym, row[2].to_i
252
+ return unless row[P_NAME] # there are no params for this object
253
+ name, flags, ref = row[P_NAME].to_sym, row[P_FLAGS].to_i
249
254
  if flags & PARAM_FLAG_ARRAY != 0
250
255
  peer[name] = [] unless peer[name]
251
256
  peer[name][fetch_value(row, flags)] = ref if ref = fetch_ref_value(row)
@@ -258,17 +263,18 @@ module DBI
258
263
  end
259
264
 
260
265
  def fetch_value row, flags
261
- return row[CI_P_INT].to_i if flags & PARAM_FLAG_INT != 0
262
- return row[CI_P_STR].to_s if flags & PARAM_FLAG_STRING != 0
263
- return instantiate(row[CI_P_REF].to_i, class_by_name(row[CI_P_REF + 2])) if flags & PARAM_FLAG_REF != 0
264
- return row[CI_P_TIME].to_time if flags & PARAM_FLAG_TIME != 0
265
- return row[CI_P_TIME].to_date if flags & PARAM_FLAG_DATE != 0
266
+ return row[P_INT].to_i if flags & PARAM_FLAG_INT != 0
267
+ return row[P_FLT].to_f if flags & PARAM_FLAG_FLOAT != 0
268
+ return row[P_STR].to_s if flags & PARAM_FLAG_STRING != 0
269
+ return instantiate(row[P_REF].to_i, row[P_REF_CLASS]) if flags & PARAM_FLAG_REF != 0
270
+ return row[P_TIME].to_time if flags & PARAM_FLAG_TIME != 0
271
+ return row[P_TIME].to_date if flags & PARAM_FLAG_DATE != 0
266
272
  return nil
267
273
  end
268
274
 
269
275
  def fetch_ref_value row
270
276
  ref_pk = nil
271
- instantiate ref_pk, class_by_name(row[8]) if ref_pk = row[6]
277
+ instantiate ref_pk, row[P_REF_CLASS] if ref_pk = row[P_REF]
272
278
  end
273
279
 
274
280
  def object_ids objects
@@ -32,6 +32,7 @@ module Memory
32
32
  end
33
33
 
34
34
  class RuntimeFactory
35
+ attr_accessor :database
35
36
  def initialize
36
37
  @pk, @database = 1001, {}
37
38
  end
@@ -44,9 +45,9 @@ module Memory
44
45
  end
45
46
 
46
47
  class Runtime < Rubernate::Runtime
47
- attr :pk, true
48
+ attr_accessor :pk, :database
48
49
 
49
- # Database is maps {pk => [class, {key => value}]}
50
+ # Database is maps {pk => [class, {attr => value}]}
50
51
  def initialize database, pk_seq
51
52
  super()
52
53
  @pk_seq, @database, @factory = pk_seq, database, Queries::Factory.new
@@ -52,7 +52,7 @@ class Class
52
52
  # Returns subclasses names (self is not included)
53
53
  attr :subclasses
54
54
 
55
- # Register +klass+ as descendant in all superclasses
55
+ # Register klass as descendant in all superclasses
56
56
  def update_superclass klass
57
57
  @subclasses ||= []
58
58
  @subclasses << klass.name if klass != self
@@ -50,8 +50,8 @@ class Peer < Hash
50
50
  yield key, old_value, value if block_given?
51
51
  end
52
52
 
53
- # This module is for including to collections of Persistent
54
- # objects. It adds fied that contains copy of collection
53
+ # This module for including to collections of Persistent
54
+ # objects. It adds field that contains copy of collection
55
55
  # and controls dirty status of collection.
56
56
  module Container
57
57
  attr_writer :copy
@@ -9,37 +9,37 @@ module Queries
9
9
 
10
10
  # Contains operations definitions
11
11
  module Operations
12
- # Declares +And+ sql clause.
12
+ # Declares And sql clause.
13
13
  def And expr1, expr2
14
14
  @factory.bin_op expr1, expr2, 'and'
15
15
  end
16
16
 
17
- # Declares +Or+ sql clause.
17
+ # Declares Or sql clause.
18
18
  def Or expr1, expr2
19
19
  @factory.bin_op expr1, expr2, 'or', true
20
20
  end
21
21
 
22
- # Declares +=+ sql clause.
22
+ # Declares = sql clause.
23
23
  def Eq expr1, expr2
24
24
  @factory.bin_op expr1, expr2, '='
25
25
  end
26
26
 
27
- # Declares +Not+ sql clause.
27
+ # Declares Not sql clause.
28
28
  def Not expr
29
29
  @factory.un_op expr, 'not', true
30
30
  end
31
31
 
32
- # Declares +is null+ sql clause
32
+ # Declares is null sql clause
33
33
  def IsNil expr
34
34
  @factory.bin_op expr, @factory.expr(nil), 'is'
35
35
  end
36
36
 
37
- # Declares +is not null+ sql clause
37
+ # Declares is not null sql clause
38
38
  def IsNotNil expr
39
39
  @factory.bin_op expr, @factory.expr(nil), 'is not'
40
40
  end
41
41
 
42
- # Declares +in+ sql clause
42
+ # Declares in sql clause
43
43
  def In expr, list
44
44
  @factory.bin_op expr, @factory.list(list), 'in'
45
45
  end
@@ -55,7 +55,7 @@ module Queries
55
55
  end
56
56
 
57
57
  # Defines query elements factory. By default it creates elements defined
58
- # in module +Generic+, but this befavior can be changed by seting of appropriate class.
58
+ # in module Generic, but this befavior can be changed by seting of appropriate class.
59
59
  # Following example changes implementation of BinOpConst
60
60
  #
61
61
  # :call-seq:
@@ -82,7 +82,7 @@ module Queries
82
82
  end
83
83
  private
84
84
  # Defines factory method that will instantiate element instance
85
- # and pass +self+ as element factory.
85
+ # and pass self as element factory.
86
86
  def self.def_factory name
87
87
  module_eval %{
88
88
  attr_writer :#{name}
@@ -212,7 +212,7 @@ module Queries
212
212
  end
213
213
  end
214
214
 
215
- # Represent +r_params+ for hashes and arrays constrained by key
215
+ # Represent r_params for hashes and arrays constrained by key
216
216
  class KeyRefExpr < BinOpConstr
217
217
  def initialize factory, r_param, key_field, key_value
218
218
  @factory, @r_param, @key_field, @key_value = factory, r_param, key_field, key_value
@@ -258,19 +258,20 @@ module Queries
258
258
  # Fields accessors.
259
259
  def pk () f_expr 'object_pk'; end
260
260
  def int () f_expr 'int_value'; end
261
+ def float() f_expr 'flt_value'; end
261
262
  def str () f_expr 'str_value'; end
262
263
  def time () f_expr 'dat_value'; end
263
- def date () f_expr 'dat_value'; end # TODO: make proper convertation
264
+ def date () f_expr 'dat_value'; end
264
265
  def ref () f_expr 'ref_value'; end
265
266
  def flags() f_expr 'flags'; end
266
267
 
267
- # The following methods checks +r_param.flags+ value. (r_param.flags)
268
+ # The following methods checks r_param.flags value. (r_param.flags)
268
269
  def is_int () Eq flags, PARAM_FLAG_INT; end
269
270
  def is_str () Eq flags, PARAM_FLAG_STRING; end
270
271
  def is_time() Eq flags, PARAM_FLAG_TIME; end
271
272
  def is_ref () Eq flags, PARAM_FLAG_REF; end
272
273
 
273
- # Shortcut for +Eq+ method
274
+ # Shortcut for Eq method
274
275
  def == expr
275
276
  expr.is_a?(RObject) ?
276
277
  @factory.bin_op(ref, expr.pk, '=') :
@@ -288,7 +289,7 @@ module Queries
288
289
  end
289
290
  end
290
291
  private
291
- # Creates +FieldExpr+ witch field of this (r_param) table
292
+ # Creates FieldExpr witch field of this (r_param) table
292
293
  def f_expr field
293
294
  @factory.field self, field
294
295
  end
@@ -368,7 +369,7 @@ module Queries
368
369
  @exprs.inject([]){|result, expr| result.concat expr.markers}
369
370
  end
370
371
 
371
- # Arranges map: +values+ {marker=>value} to ordered array of values
372
+ # Arranges map: values {marker=>value} to ordered array of values
372
373
  # accroding to markers in query.
373
374
  def params values
374
375
  markers.inject([]){|r, m| r << values[m]}
@@ -403,18 +404,18 @@ module Queries
403
404
  @evaluated = true
404
405
  end
405
406
 
406
- # Generates +where+ clause for each expression joined by +and+ clause
407
+ # Generates where clause for each expression joined by and clause
407
408
  def where_sql
408
409
  r_params.collect{|rp| rp.to_sql + '.name = \'' + rp.name + '\''}.concat(
409
410
  @exprs.collect{|ex| ex.to_sql}).join(" and\n\t\t")
410
411
  end
411
412
 
412
- # Generates +order by+ sql clause
413
+ # Generates order by sql clause
413
414
  def order_by_sql
414
415
  @order.collect{|ord| ord.to_sql}.join(', ')
415
416
  end
416
417
 
417
- # Generates left outer join for each +r_params+ used in query
418
+ # Generates left outer join for each r_params used in query
418
419
  def tables_sql
419
420
  r_objects.collect{|r_object| 'r_objects ' + r_object.to_sql}.join(', ') +
420
421
  r_params.collect{|r_param|
@@ -423,7 +424,7 @@ module Queries
423
424
  }.join()
424
425
  end
425
426
 
426
- # Retruns +r_params+ used in query. List of +RParam+.
427
+ # Retruns r_params used in query. List of RParam.
427
428
  def r_params
428
429
  res = @exprs.inject([]) {|res, exp| res.concat exp.r_params}
429
430
  @order.inject(res) {|res, ord| res.concat ord.r_params}
@@ -431,7 +432,7 @@ module Queries
431
432
  res
432
433
  end
433
434
 
434
- # Retruns +r_objects+ used in query. List of +RObject+.
435
+ # Retruns r_objects used in query. List of RObject.
435
436
  def r_objects
436
437
  res = (@r_objects.values + r_params.inject([]){|res, rp| res << rp.r_object})
437
438
  res.uniq!
@@ -1,6 +1,5 @@
1
1
  module Rubernate
2
- # Base class for all "Runtime+ implementations.
3
- # Most of these methods should be overriden by subclasses.
2
+ # Base class for all Runtime implementations.
4
3
  class Runtime
5
4
  include Callbacks::Runtime
6
5
 
@@ -116,20 +115,32 @@ module Rubernate
116
115
  end
117
116
 
118
117
  private
119
- # Creates new object instance or returns pooled one
118
+ # Creates new object instance or returns insance from pool
119
+ # Parameter klass can be Class or String (class name)
120
120
  def instantiate pk, klass, peer = nil
121
121
  object = @pool[pk]
122
- if object and object.class != klass
123
- raise "invalid class #{klass} of object pk: #{pk}: #{object.class}"
124
- end
125
122
  unless object
126
- object, object.primary_key = klass.allocate, pk
123
+ clazz = klass.is_a?(Class) ? klass : get_class(klass)
124
+ object = clazz ? clazz.allocate : FakeEntity.new(klass)
125
+ object.primary_key = pk
127
126
  @pool[pk] = object
128
127
  end
129
- object.peer = peer
128
+ object.peer = peer # TODO: TEST!!! and write description
130
129
  object
131
130
  end
132
-
131
+
132
+ #Classes cache.
133
+ @@classes = {}
134
+
135
+ # Returns class with specified name or nil if there is no one.
136
+ def get_class name
137
+ klass = @@classes[name]
138
+ return klass if klass
139
+ klass = Module.find_class name
140
+ return nil unless klass
141
+ @@classes[name] = klass
142
+ end
143
+
133
144
  # Returns modified objects.
134
145
  def modified
135
146
  @pool.values.find_all {|object| object.peer and object.dirty?}
@@ -192,24 +203,20 @@ module Rubernate
192
203
  when Class: p.name
193
204
  else p
194
205
  end
195
- end
196
-
197
- # TODO: continue from here!!!
198
- class FakeEntity
199
- persistent
200
- def method_not_defined
201
- raise 'object #{primary_key} has undefined class'
202
- end
203
- end
204
-
205
- @@classes = {}
206
- # Returns class with specified name or throw error if there is on one.
207
- def class_by_name name
208
- klass = @@classes[name]
209
- return klass if klass
210
- klass = Module.find_class name
211
- @@classes[name] = klass if klass
212
- klass
213
- end
206
+ end
207
+ end
208
+
209
+ # Represetns fake entity. - objects whose class wasn't found during loading.
210
+ class FakeEntity
211
+ persistent
212
+ def initialize class_name
213
+ @class_name = class_name
214
+ end
215
+ def method_missing name, *args
216
+ raise ObjectLoadError.new("class: #{@class_name} not found for object: #{primary_key}")
217
+ end
218
+ def to_s
219
+ "Fake Entity: #{primaty_key}, for class: #{@class_name}"
220
+ end
214
221
  end
215
222
  end
data/lib/rubernate.rb CHANGED
@@ -35,6 +35,9 @@ require 'rubernate/impl/dbimysql'
35
35
  require 'rubernate/impl/dbioracle'
36
36
 
37
37
 
38
+
39
+ # Contains most useful methods. This module is included
40
+ # in all persistent classes.
38
41
  module Rubernate
39
42
  # Common Rubernate Log instance
40
43
  Log = Log4r::Logger.new self.name
@@ -42,7 +45,7 @@ module Rubernate
42
45
  # Rubernate core singelton methods.
43
46
  class << self
44
47
  # Allows you setup Rubernate by yours implementaion of RuntimeFactory.
45
- # See also method configure
48
+ # See also method config
46
49
  def runtime_factory= factory
47
50
  Log.info "Rubernate configured by #{factory}"
48
51
  @runtime_factory = factory
@@ -124,4 +127,8 @@ module Rubernate
124
127
  @msg
125
128
  end
126
129
  end
130
+
131
+ # Signals about errors occured during object loading.
132
+ class ObjectLoadError < RuntimeError
133
+ end
127
134
  end
data/tests/config.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Set to true to run tests or Oracle
2
- $run_oracle_tests = true
2
+ $run_oracle_tests = false
3
3
 
4
4
  ORA_RUNTIME_CLASS = Rubernate::DBI::OracleRuntime
5
5
  ORA_DB_URL = 'dbi:OCI8:dbg91'
@@ -7,7 +7,7 @@ ORA_DB_USER = 'netcracker65'
7
7
  ORA_DB_PWD = 'netcracker65'
8
8
 
9
9
  # Set to true to run tests on MySQL
10
- $run_mysql_tests = true
10
+ $run_mysql_tests = false
11
11
 
12
12
  MYSQL_RUNTIME_CLASS = Rubernate::DBI::MySqlRuntime
13
13
  MYSQL_DB_URL = 'dbi:Mysql:rubernate_db:localhost'
@@ -23,5 +23,8 @@ module FixtureClasses
23
23
  def initialize pk = nil
24
24
  @primary_key = pk
25
25
  end
26
- end
26
+ end
27
+ class Full
28
+ persistent :p_nil, :p_int, :p_float, :p_str, :p_date, :p_time, :p_array, :p_hash
29
+ end
27
30
  end
@@ -130,6 +130,7 @@ module DBI::GenericTests
130
130
  assert_equal o.primary_key, row['OBJECT_PK'].to_i
131
131
  assert_equal PARAM_FLAG_INT | PARAM_FLAG_HASH, row['FLAGS'].to_i
132
132
  assert hash.has_key?(row['INT_VALUE'].to_i)
133
+ assert_nil row['FLT_VALUE']
133
134
  assert_nil row['STR_VALUE']
134
135
  assert_nil row['DAT_VALUE']
135
136
  assert_equal hash[row['INT_VALUE'].to_i].primary_key, row['REF_VALUE'].to_i
@@ -156,17 +157,19 @@ module DBI::GenericTests
156
157
  if row['FLAGS'].to_i == HASH_INT_REF
157
158
  assert_equal o.primary_key, row['OBJECT_PK'].to_i
158
159
  assert hash.has_key?(row['INT_VALUE'].to_i)
160
+ assert_nil row['FLT_VALUE']
159
161
  assert_nil row['STR_VALUE']
160
162
  assert_nil row['DAT_VALUE']
161
163
  assert_equal hash[row['INT_VALUE'].to_i].primary_key, row['REF_VALUE'].to_i
162
164
  elsif row['FLAGS'].to_i == HASH_STRING_REF
163
165
  assert_equal o.primary_key, row['OBJECT_PK'].to_i
164
166
  assert_nil row['INT_VALUE']
167
+ assert_nil row['FLT_VALUE']
165
168
  assert hash.has_key?(row['STR_VALUE'])
166
169
  assert_nil row['DAT_VALUE']
167
170
  assert_equal hash[row['STR_VALUE']].primary_key, row['REF_VALUE'].to_i
168
171
  else
169
- flunk 'Invalid flags ' + row['FLAGS'].to_i
172
+ flunk 'Invalid flags: ' + row['FLAGS'].to_i
170
173
  end
171
174
  end
172
175
  end
@@ -286,8 +289,8 @@ module DBI::GenericTests
286
289
  Rubernate.session {o = C1.new.attach; o.p1 = {time => o}; pk = o.primary_key}
287
290
  Rubernate.session {
288
291
  o = find_by_pk pk
289
- assert_equal 1, o.p1.size
290
- _time, _obj = o.p1.shift
292
+ assert_equal 1, o.p1.size # check hash size
293
+ _time, _obj = o.p1.shift # get hash value
291
294
  assert_equal time.to_a[0..5], _time.to_a[0..5] # Ignore time-zone
292
295
  assert_equal o, _obj
293
296
  }
@@ -298,8 +301,8 @@ module DBI::GenericTests
298
301
  Rubernate.session {o = C1.new.attach; o.p1 = {date => o}; pk = o.primary_key}
299
302
  Rubernate.session {
300
303
  o = find_by_pk pk
301
- assert_equal 1, o.p1.size
302
- _date, _obj = o.p1.shift
304
+ assert_equal 1, o.p1.size # check hash size
305
+ _date, _obj = o.p1.shift # get hash value
303
306
  assert_equal date, _date
304
307
  assert_equal o, _obj
305
308
  }
@@ -345,7 +348,52 @@ module DBI::GenericTests
345
348
  o = find_by_pk pk
346
349
  assert_equal ({}), o.p1
347
350
  end
348
- end
351
+ end
352
+
353
+ def test_param_all_types
354
+ pk, time, date = nil, Time.now, Date.today
355
+ Rubernate.session do
356
+ o = Full.new.attach
357
+ pk = o.primary_key
358
+ o.p_nil = nil
359
+ o.p_int = 123
360
+ o.p_float = 77.5
361
+ o.p_str = 'Test String'
362
+ o.p_time = time
363
+ o.p_date = date
364
+ o.p_array = [o, o, o]
365
+ o.p_hash = {nil => o,
366
+ 777 => o,
367
+ 1.23 => o,
368
+ 'Str.Key' => o,
369
+ time => o,
370
+ date => o
371
+ }
372
+ end
373
+ Rubernate.session do
374
+ o = find_by_pk pk
375
+ assert_nil o.p_nil
376
+ assert_equal 123, o.p_int
377
+ assert_equal 77.5, o.p_float
378
+ assert_equal 'Test String', o.p_str
379
+ assert_equal time.to_a[0..5], o.p_time.to_a[0..5] # Ignore time zone
380
+ assert_equal date, o.p_date # Ignore time zone
381
+ assert_equal [o, o, o], o.p_array
382
+ assert_equal 6, o.p_hash.size
383
+
384
+ o.p_hash.each {|key, val|
385
+ assert_equal time.to_a[0..5], key.to_a[0..5] if key.is_a? Time
386
+ assert_equal date, key if key.is_a? Date
387
+ }
388
+ o.p_hash.delete_if {|key, val| key.is_a? Time or key.is_a? Date}
389
+
390
+ assert_equal ({nil => o,
391
+ 777 => o,
392
+ 1.23 => o,
393
+ 'Str.Key' => o
394
+ }), o.p_hash
395
+ end
396
+ end
349
397
  end
350
398
 
351
399
  module GenericRuntimeTests
@@ -251,15 +251,15 @@ class Rubernate::BaseRuntimeTest < Test::Unit::TestCase
251
251
  end
252
252
 
253
253
  def test_instantiate
254
- object = @runtime.instantiate 1, C1
254
+ object = @runtime.instantiate 1, C1.name
255
255
  assert object
256
256
  assert_equal 1, object.primary_key
257
257
  assert_equal C1, object.class
258
258
  end
259
259
 
260
260
  def test_instantiate_existing
261
- o0 = @runtime.instantiate 1, C1
262
- o1 = @runtime.instantiate 1, C1
261
+ o0 = @runtime.instantiate 1, C1.name
262
+ o1 = @runtime.instantiate 1, C1.name
263
263
 
264
264
  assert o0.equal?(o1)
265
265
  assert_equal o0, o1
@@ -284,10 +284,15 @@ class Rubernate::BaseRuntimeTest < Test::Unit::TestCase
284
284
  assert_equal o_.object_id, o__.object_id
285
285
  end
286
286
  end
287
-
288
- def test_instantiate_invalid_class
289
- @runtime.instantiate 1, C1
290
- assert_raise(RuntimeError) { @runtime.instantiate 1, C2 }
287
+
288
+ def test_instantiate_fake_class
289
+ @factory.database = {27 => ['NoSuchClass', {}]}
290
+ Rubernate.session do
291
+ o = find_by_pk 27
292
+ assert_equal FakeEntity, o.class
293
+ assert_equal 27, o.primary_key
294
+ assert_raise(ObjectLoadError) {o.test}
295
+ end
291
296
  end
292
297
 
293
298
  def test_modified
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: Rubernate
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-03-06 00:00:00 +03:00
6
+ version: 0.1.1
7
+ date: 2006-03-07 00:00:00 +03:00
8
8
  summary: Object-oriented storage for Ruby objects based on relational database model
9
9
  require_paths:
10
10
  - lib