Rubernate 0.1.0 → 0.1.1

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/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