Rubernate 0.1.6 → 0.1.7

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/lib/rubernate.rb CHANGED
@@ -37,6 +37,7 @@ module Rubernate
37
37
  require 'rubernate/peer'
38
38
  require 'rubernate/runtime'
39
39
  require 'rubernate/queries'
40
+ require 'rubernate/impl/dbi_genpk'
40
41
 
41
42
  # Rubernate core singelton methods.
42
43
  class << self
@@ -53,14 +54,14 @@ module Rubernate
53
54
  # * user - databases user name
54
55
  # * password - databases users password
55
56
  def config db, url, user, password
56
- impl, init = case db
57
+ impl, init, gen = case db
57
58
  when :mysql : require_mysql
58
59
  when :oracle: require_oracle
59
60
  when :pg : require_pg
60
61
  when :memory: require_memory
61
62
  else raise "Database #{db} not supported"
62
63
  end
63
- self.configuration = DBI::Configuration.new impl, init, url, user, password
64
+ self.configuration = DBI::Configuration.new impl, init, gen, url, user, password
64
65
  end
65
66
 
66
67
 
@@ -108,21 +109,21 @@ module Rubernate
108
109
  def require_mysql # :nodoc:
109
110
  require 'rubernate/impl/dbi_mysql'
110
111
  require 'rubernate/init/init_mysql'
111
- [DBI::MySqlRuntime, DBI::MySqlInit.new]
112
+ [DBI::MySqlRuntime, DBI::MySqlInit.new, nil]
112
113
  end
113
114
 
114
115
  # Loads Oracle module
115
116
  def require_oracle # :nodoc:
116
117
  require 'rubernate/impl/dbi_oracle'
117
118
  require 'rubernate/init/init_oracle'
118
- [DBI::OracleRuntime, DBI::OracleInit.new]
119
+ [DBI::OracleRuntime, DBI::OracleInit.new, DBI::OraPKChunkFactory.new]
119
120
  end
120
121
 
121
122
  # Loads Postgres module
122
123
  def require_pg # :nodoc:
123
124
  require 'rubernate/impl/dbi_pg'
124
125
  require 'rubernate/init/init_pg'
125
- [DBI::PgRuntime, DBI::PgInit.new]
126
+ [DBI::PgRuntime, DBI::PgInit.new, DBI::PgPKChunkFactory.new]
126
127
  end
127
128
 
128
129
  # Loads Memory module used only for testing :nodoc:
@@ -31,15 +31,16 @@ module DBI
31
31
  P_TIME = 6
32
32
  P_REF = 7
33
33
 
34
- # Holds configuration information and serves as factory for Runtime objects.
34
+ # Holds configuration information and serves as factory for Runtime objects.
35
35
  class Configuration
36
36
  # Accepts Runtime impl class, db initializer class, database url, user name, and user password
37
- def initialize klass, init, db_url, db_user, db_password
37
+ def initialize klass, init, pkcf, db_url, db_user, db_password
38
38
  @klass, @init, @db_url, @db_user, @db_password = klass, init, db_url, db_user, db_password
39
+ PKGenerator.chunk_factory = pkcf
39
40
  # @params = {'AutoCommit' => false} #TODO: refine
40
41
  end
41
-
42
- # Creates initialized PeerHost
42
+
43
+ # Creates initialized Runtime
43
44
  def create
44
45
  @klass.new connect
45
46
  end
@@ -68,12 +69,16 @@ module DBI
68
69
  class Runtime < Rubernate::Runtime
69
70
  include DBI
70
71
 
71
- # In some implementations parameters are deleted automatically with corresponding r_object records
72
- DELETE_PARAMS = <<-SQL
73
- DELETE FROM R_PARAMS WHERE OBJECT_PK = ?
72
+ DELETE_PARAMS = <<-SQL
73
+ DELETE FROM R_PARAMS WHERE OBJECT_PK = ? AND NAME = ?
74
74
  SQL
75
- DELETE_PARAMS_FOR = <<-SQL
76
- DELETE FROM R_PARAMS WHERE OBJECT_PK IN
75
+ INSERT_PARAMS = <<-SQL
76
+ INSERT INTO R_PARAMS VALUES (?, ?, ?, ?, ?, ?, ?, ?)
77
+ SQL
78
+ UPDATE_PARAMS = <<-SQL
79
+ UPDATE R_PARAMS SET FLAGS = ?, INT_VALUE = ?, FLT_VALUE = ?,
80
+ STR_VALUE = ?, DAT_VALUE = ?, REF_VALUE = ?
81
+ WHERE OBJECT_PK = ? AND NAME = ?
77
82
  SQL
78
83
  DELETE_OBJECT = <<-SQL
79
84
  DELETE FROM R_OBJECTS WHERE OBJECT_PK = ?
@@ -81,9 +86,6 @@ module DBI
81
86
  CREATE_PEER = <<-SQL
82
87
  INSERT INTO R_OBJECTS (OBJECT_PK, OBJECT_CLASS) values (?, ?)
83
88
  SQL
84
- SAVE_PARAMS = <<-SQL
85
- INSERT INTO R_PARAMS VALUES (?, ?, ?, ?, ?, ?, ?, ?)
86
- SQL
87
89
  SELECT_PARAMS = <<-SQL
88
90
  SELECT P.*, R.OBJECT_CLASS, O.OBJECT_CLASS
89
91
  FROM R_PARAMS P JOIN R_OBJECTS O ON (O.OBJECT_PK = P.OBJECT_PK)
@@ -113,21 +115,13 @@ module DBI
113
115
  # Updates object state in database
114
116
  def save objects
115
117
  objects = [objects] unless objects.kind_of? Array
116
- return if objects.empty?
117
- # clear r_params for objects
118
- clear_params objects
119
- # store r_params for objects
120
- @dbh.prepare SAVE_PARAMS do |sth|
121
- for object in objects
122
- object.__peer.each {|name, param|
123
- save_param sth, object, name.to_s, param
124
- }
125
- end
126
- end
127
- # clear dirty flag
128
- for object in objects
129
- object.__peer.dirty = false
130
- end
118
+ return if objects.empty?
119
+ # gather parameters changes
120
+ create, delete, update, insert = gather_changes objects
121
+ bulk_o_create create unless create.empty? # create virtual objects
122
+ bulk_p_delete delete unless delete.empty? # delete params
123
+ bulk_p_update update unless update.empty? # update params
124
+ bulk_p_insert insert unless insert.empty? # insert params
131
125
  end
132
126
 
133
127
  # Loads object by primary_key
@@ -173,7 +167,8 @@ module DBI
173
167
  @dbh.rollback rescue Log.error 'Error during rollback in session failed state'
174
168
  @dbh.disconnect rescue Log.error 'Error during disconnect in session failed state'
175
169
  end
176
- private
170
+
171
+ private
177
172
  # Select objects from database by query and determines objects
178
173
  # that should be loaded and put them to buffer.
179
174
  def find_buffer query, params, buffer
@@ -197,45 +192,117 @@ module DBI
197
192
  }
198
193
  }
199
194
  end
200
-
201
- # Delete entries corresponding to objects from r_params
202
- def clear_params objects
203
- @dbh.do DELETE_PARAMS_FOR + object_ids_p(objects)
195
+
196
+ # Returns tree arrays [delete, update, insert] each of which consist of two values [object, attr_name]
197
+ def gather_changes objects
198
+ create, delete, update, insert = [], [], [], []
199
+ for obj in objects
200
+ create << obj if obj.__virtual?
201
+ for attr, change in obj.__peer.change_track
202
+ track, value = [obj, attr], obj.__peer[attr]
203
+ if change == :inserted # New values shoud be inserted
204
+ insert << track unless value.is_a? Persistent and ref_lost? obj, attr, value
205
+ else # Updated values should be considered by another way
206
+ case value
207
+ when Rubernate::Peer::Container : # Collections
208
+ delete << track # first delete all values
209
+ insert << track # second insert again all values
210
+ when Persistent :
211
+ if ref_lost? obj, attr, value
212
+ delete << track
213
+ else
214
+ update << track
215
+ end
216
+ when nil: delete << track
217
+ else update << track # just update record in database
218
+ end
219
+ end
220
+ end
221
+ obj.__virtual = false # reset virtual flag
222
+ obj.__peer.dirty = false # reset dirty flag
223
+ end
224
+ [create, delete, update, insert]
204
225
  end
205
226
 
227
+ def bulk_o_create objects
228
+ @dbh.prepare CREATE_PEER do |sth|
229
+ objects.each {|obj| sth.execute obj.primary_key, obj.class.name}
230
+ end
231
+ end
232
+
233
+ def bulk_p_delete params
234
+ @dbh.prepare DELETE_PARAMS do |sth|
235
+ params.each {|obj, attr| sth.execute obj.primary_key, attr.to_s}
236
+ end
237
+ end
238
+
239
+ def bulk_p_insert params
240
+ @dbh.prepare INSERT_PARAMS do |sth|
241
+ params.each {|obj, attr|
242
+ save_param sth, obj, attr.to_s, obj.__peer[attr]
243
+ }
244
+ end
245
+ end
246
+
247
+ def bulk_p_update params
248
+ @dbh.prepare UPDATE_PARAMS do |sth|
249
+ params.each {|obj, attr|
250
+ update_param sth, obj.primary_key, attr.to_s, obj.__peer[attr]
251
+ }
252
+ end
253
+ end
254
+
206
255
  def save_param sth, obj, name, param
207
256
  case param
208
257
  when Persistent: save_ref sth, obj, name, param
209
258
  when Hash: save_hash sth, obj, name, param
210
259
  when Array: save_array sth, obj, name, param
211
- when Integer: save_int sth, obj.primary_key, name, param
212
- when Float: save_float sth, obj.primary_key, name, param
213
- when Time: save_time sth, obj.primary_key, name, param
214
- when Date: save_date sth, obj.primary_key, name, param
215
- else save_str sth, obj.primary_key, name, param.to_s
260
+ when Integer: sth.execute obj.primary_key, name, *row_fmt_int(param)
261
+ when Float: sth.execute obj.primary_key, name, *row_fmt_float(param)
262
+ when Time: sth.execute obj.primary_key, name, *row_fmt_time(param)
263
+ when Date: sth.execute obj.primary_key, name, *row_fmt_date(param)
264
+ else sth.execute obj.primary_key, name, *row_fmt_str(param)
216
265
  end
217
266
  end
218
-
219
- def save_int sth, pk, name, int
220
- sth.execute pk, name, PARAM_FLAG_INT, int, nil, nil, nil, nil
267
+
268
+ def update_param sth, pk, name, param
269
+ row_fmt = case param
270
+ when Persistent: row_fmt_ref param
271
+ when Integer: row_fmt_int param
272
+ when Float: row_fmt_float param
273
+ when Time: row_fmt_time param
274
+ when Date: row_fmt_date param
275
+ when Hash: raise 'internal error Hash is not supposed to be updated'
276
+ when Array: raise 'internal error Array is not supposed to be updated'
277
+ else row_fmt_str param # It's supposed to be string here
278
+ end
279
+ sth.execute *(row_fmt << pk << name)
221
280
  end
222
281
 
223
- def save_float sth, pk, name, float
224
- sth.execute pk, name, PARAM_FLAG_FLOAT, nil, float, nil, nil, nil
282
+ def row_fmt_int int
283
+ [PARAM_FLAG_INT, int, nil, nil, nil, nil]
225
284
  end
226
-
227
- def save_str sth, pk, name, str
228
- sth.execute pk, name, PARAM_FLAG_STRING, nil, nil, str, nil, nil
229
- end
230
285
 
231
- def save_time sth, pk, name, time
232
- sth.execute pk, name, PARAM_FLAG_TIME, nil, nil, nil, TimeType.new(time), nil
286
+ def row_fmt_float float
287
+ [PARAM_FLAG_FLOAT, nil, float, nil, nil, nil]
288
+ end
289
+
290
+ def row_fmt_str str
291
+ [PARAM_FLAG_STRING, nil, nil, str, nil, nil]
292
+ end
293
+
294
+ def row_fmt_time time
295
+ [PARAM_FLAG_TIME, nil, nil, nil, TimeType.new(time), nil]
296
+ end
297
+
298
+ def row_fmt_date time
299
+ [PARAM_FLAG_DATE, nil, nil, nil, TimeType.new(time), nil]
300
+ end
301
+
302
+ def row_fmt_ref obj
303
+ [PARAM_FLAG_REF, nil, nil, nil, nil, obj.primary_key]
233
304
  end
234
305
 
235
- def save_date sth, pk, name, date
236
- sth.execute pk, name, PARAM_FLAG_DATE, nil, nil, nil, TimeType.new(date), nil
237
- end
238
-
239
306
  def save_ref sth, obj, name, ref
240
307
  sth.execute obj.primary_key, name, PARAM_FLAG_REF, nil, nil, nil, nil,
241
308
  ref.primary_key unless ref_lost? obj, name, ref
@@ -258,8 +325,7 @@ module DBI
258
325
  when ::Date: sth.execute pk, name, HASH_DATE_REF, nil, nil, nil, TimeType.new(key), ref
259
326
  when ::Time: sth.execute pk, name, HASH_TIME_REF, nil, nil, nil, TimeType.new(key), ref
260
327
  when nil: sth.execute pk, name, PARAM_FLAG_HASH, nil, nil, nil, nil, ref
261
- else
262
- raise "invalid hash key value #{key}"
328
+ else raise "invalid hash key value #{key}"
263
329
  end
264
330
  end
265
331
 
@@ -0,0 +1,67 @@
1
+ require 'thread'
2
+
3
+ module Rubernate
4
+ module DBI
5
+ class PKChunk
6
+ def initialize first, size
7
+ @next, @limit = first, first + size
8
+ end
9
+ def empty?
10
+ @next >= @limit
11
+ end
12
+ def get_pk
13
+ @next+= 1
14
+ @next - 1
15
+ end
16
+ end
17
+
18
+ class PKChunkFactory
19
+ PK_CHUNCK_SIZE = 25 # Pk chunck size (step of sequence).
20
+
21
+ # Returns new chunk
22
+ def create dbh
23
+ PKChunk.new dbh.select_all(@get_from_seq)[0][0].to_i, PK_CHUNCK_SIZE
24
+ end
25
+ end
26
+
27
+ # Represents primary key generator
28
+ class PKGenerator
29
+ class << self
30
+ attr_accessor :chunk_factory
31
+
32
+ # Gets PKGenerator instance
33
+ def instance
34
+ PKGenerator.new
35
+ end
36
+
37
+ @@chunk_pool_lock = Mutex.new
38
+ @@chunk_pool = []
39
+ # Acquires chunk
40
+ def acquire_chunk dbh
41
+ @@chunk_pool_lock.synchronize {
42
+ return @@chunk_pool.shift unless @@chunk_pool.empty?
43
+ }
44
+ self.chunk_factory.create dbh
45
+ end
46
+ # Release chunk
47
+ def release_chunk chunk
48
+ @@chunk_pool_lock.synchronize {
49
+ @@chunk_pool << chunk
50
+ }
51
+ end
52
+ end
53
+
54
+ # Generates pk.
55
+ def generate dbh
56
+ @chunk = self.class.acquire_chunk dbh if @chunk.nil? or @chunk.empty?
57
+ @chunk.get_pk
58
+ end
59
+
60
+ # Should be invoked at the end of the session.
61
+ def release
62
+ self.class.release_chunk @chunk if @chunk and !@chunk.empty?
63
+ @chunk = nil
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,4 +1,5 @@
1
1
  require 'dbi'
2
+ require 'rubernate/impl/dbi_genpk'
2
3
  require 'rubernate/impl/dbi_generic'
3
4
 
4
5
  module Rubernate
@@ -1,34 +1,43 @@
1
1
  require 'dbi'
2
+ require 'rubernate/impl/dbi_genpk'
2
3
  require 'rubernate/impl/dbi_generic'
3
4
 
4
5
  module Rubernate
5
6
  module DBI
6
- class OracleRuntime < Runtime
7
+ class OraPKChunkFactory < PKChunkFactory
7
8
  SELECT_NEXT_PK = <<-SQL
8
9
  SELECT R_PK_SEQUENCE.NEXTVAL FROM DUAL
9
10
  SQL
10
-
11
+ def initialize
12
+ @get_from_seq = SELECT_NEXT_PK
13
+ end
14
+ end
15
+
16
+ class OracleRuntime < Runtime
17
+ def initialize dbh
18
+ super
19
+ @pk_gen = PKGenerator.new
20
+ end
21
+
11
22
  # Creates record in r_objects for specified object
12
23
  def create object
13
24
  object.__peer = Rubernate::Peer.new unless object.__peer
14
- object.primary_key = @dbh.select_one(SELECT_NEXT_PK)[0].to_i
15
- @dbh.do CREATE_PEER, object.primary_key, object.class.name
25
+ object.primary_key = @pk_gen.generate @dbh
26
+ object.__virtual = true
16
27
  object.__peer.dirty = true
17
28
  object.primary_key
18
- end
29
+ end
30
+
31
+ def close
32
+ super
33
+ @pk_gen.release
34
+ end
35
+
36
+ def failed
37
+ @pk_gen.release
38
+ end
19
39
 
20
40
  private
21
- # Oracle requires that IN list must be less or equal to 1000 items
22
- def clear_params objects
23
- return super if objects.size <= 1000
24
- idx = 0
25
- while chunck = objects.slice(idx, 1000)
26
- break if chunck.empty?
27
- super chunck
28
- idx+= chunck.size
29
- end
30
- end
31
-
32
41
  # Oracle requires that IN list must be less or equal to 1000 items
33
42
  def load_buffer buffer
34
43
  return super if buffer.size <= 1000
@@ -3,30 +3,40 @@ require 'rubernate/impl/dbi_generic'
3
3
 
4
4
  module Rubernate
5
5
  module DBI
6
- class PgRuntime < Runtime
6
+ class PgPKChunkFactory < PKChunkFactory
7
7
  SELECT_NEXT_PK = <<-SQL
8
8
  SELECT NEXTVAL('R_PK_SEQUENCE')
9
9
  SQL
10
-
10
+ def initialize
11
+ @get_from_seq = SELECT_NEXT_PK
12
+ end
13
+ end
14
+
15
+ class PgRuntime < Runtime
11
16
  # Invokes super and then issues 'BEGIN'
12
17
  def initialize dbh
13
18
  super
14
19
  dbh.do 'BEGIN'
20
+ @pk_gen = PKGenerator.new
15
21
  end
16
22
 
17
23
  # Creates record in r_objects for specified object
18
24
  def create object
19
25
  object.__peer = Rubernate::Peer.new unless object.__peer
20
- object.primary_key = @dbh.select_one(SELECT_NEXT_PK)[0].to_i
21
- @dbh.do CREATE_PEER, object.primary_key, object.class.name
26
+ object.primary_key = @pk_gen.generate @dbh
27
+ object.__virtual = true
22
28
  object.__peer.dirty = true
23
29
  object.primary_key
24
30
  end
25
-
31
+
26
32
  # Issues 'COMMIT' against database.
27
33
  def close
28
34
  dbh.do 'COMMIT'
29
- super
35
+ @pk_gen.release
36
+ end
37
+
38
+ def failed
39
+ @pk_gen.release
30
40
  end
31
41
  end
32
42
  end
@@ -30,7 +30,7 @@ module DBI
30
30
  CREATE INDEX R_P_PK_NAME ON R_PARAMS (OBJECT_PK, NAME)
31
31
  }.gsub(INDENT, '')
32
32
  CREATE_R_PK_SEQUENCE = %q{
33
- CREATE SEQUENCE R_PK_SEQUENCE START WITH 1001 INCREMENT BY 1
33
+ CREATE SEQUENCE R_PK_SEQUENCE START WITH 1001 INCREMENT BY 25
34
34
  }.gsub(INDENT, '')
35
35
 
36
36
  TEMPLATE = %q{
@@ -27,7 +27,7 @@ module DBI
27
27
  CREATE INDEX R_O_CLASS ON R_OBJECTS (OBJECT_CLASS)
28
28
  }.gsub(INDENT, '')
29
29
  CREATE_R_PK_SEQUENCE = %q{
30
- CREATE SEQUENCE R_PK_SEQUENCE;
30
+ CREATE SEQUENCE R_PK_SEQUENCE INCREMENT BY 25;
31
31
  }.gsub(INDENT, '')
32
32
 
33
33
  TEMPLATE = %q{
@@ -1,10 +1,25 @@
1
+ require 'set'
2
+
1
3
  module Rubernate
2
4
  # Represent objects peer - properties holder.
3
5
  class Peer < Hash
6
+ # Retrus change track of attribute modifications
7
+ # Hash {p_name => :inserted, :}
8
+ def change_track
9
+ @change_track ||= Hash.new
10
+ each do |name, value|
11
+ if value.is_a? Container and not @change_track.has_key? name
12
+ @change_track[name] = :modified if value.recall
13
+ end
14
+ end
15
+ @change_track
16
+ end
17
+
4
18
  # Sets peers dirty flag to specified value.
5
19
  # And resets dirty flag for all properites which stored in this peer.
6
20
  def dirty= f_dirty
7
21
  @dirty = f_dirty
22
+ @change_track = nil unless f_dirty
8
23
  for value in values
9
24
  value.memorize! if value.is_a? Container
10
25
  end
@@ -13,7 +28,7 @@ class Peer < Hash
13
28
  # If peers dirty flag set to true returns it immediately
14
29
  # else iterate over all properties and returns true if dirty
15
30
  # property apperas. +on_modify+ callback invoked if dirty is +true+.
16
- def dirty? &on_modify
31
+ def dirty?
17
32
  return true if @dirty
18
33
  f_dirty, name, value, old_value = false
19
34
  each do |name, value|
@@ -21,6 +36,7 @@ class Peer < Hash
21
36
  old_value = value.recall
22
37
  if old_value
23
38
  f_dirty = dirty = true
39
+ update_track name, :modified
24
40
  break
25
41
  end
26
42
  end
@@ -47,6 +63,7 @@ class Peer < Hash
47
63
  else
48
64
  delete key
49
65
  end
66
+ update_track key, change_type(old_value, value)
50
67
  yield key, old_value, value if block_given?
51
68
  end
52
69
 
@@ -66,5 +83,17 @@ class Peer < Hash
66
83
  return self != @copy ? @copy : nil
67
84
  end
68
85
  end
86
+
87
+ private
88
+ def change_type old_value, new_value
89
+ return :inserted if old_value.nil?
90
+ return :inserted if old_value.is_a? Persistent and old_value.removed?
91
+ return :modified
92
+ end
93
+
94
+ def update_track key, type
95
+ @change_track ||= Hash.new
96
+ @change_track[key] = type unless @change_track.has_key? key
97
+ end
69
98
  end
70
99
  end
@@ -48,12 +48,22 @@ module Persistent
48
48
  @__peer = value
49
49
  end
50
50
  end
51
+
52
+ # This property is implementation internal and should not be used by users.
53
+ attr_writer :__virtual # :nodoc:
54
+
55
+ # This property indicates that object is virtual i.e. not stored in database.
56
+ def __virtual? # :nodoc:
57
+ @__virtual
58
+ end
51
59
 
52
60
  # Defines metod == in for rubernated classes
53
61
  def self.included klass
54
62
  klass.module_eval %{
55
63
  def == other
56
- return self.primary_key == other.primary_key if other.is_a? Persistent
64
+ return false unless other.is_a? Persistent
65
+ return false if self.removed? or other.removed?
66
+ return self.primary_key == other.primary_key
57
67
  super
58
68
  end
59
69
  }
@@ -334,8 +334,7 @@ module Queries
334
334
  @pk, @klass = @factory.field(self, 'object_pk'), @factory.field(self, 'object_class')
335
335
  end
336
336
 
337
- # Fiends access expressions
338
- attr_reader :pk, :klass, :to_sql
337
+ attr_reader :pk, :klass, :to_sql
339
338
 
340
339
  # Creates subclasses constraint
341
340
  def derived klass
@@ -12,8 +12,8 @@ module DBI::GenericTests
12
12
  include DBI
13
13
  include FixtureClasses
14
14
 
15
- def init rt_class, db_url, db_user, db_password
16
- @factory = Configuration.new rt_class, nil, db_url, db_user, db_password
15
+ def init rt_class, gen, db_url, db_user, db_password
16
+ @factory = Configuration.new rt_class, nil, gen, db_url, db_user, db_password
17
17
  @factory.connect {|dbh|
18
18
  dbh.do 'delete from r_params'
19
19
  dbh.do 'delete from r_objects'
@@ -44,10 +44,12 @@ module DBI::GenericTests
44
44
  o = C1.new
45
45
  o.__peer = Peer.new
46
46
  @runtime.create o
47
+ @runtime.save o
48
+
47
49
  rows = @runtime.dbh.select_all 'select * from r_objects'
48
50
  assert_equal 1, rows.size
49
51
  assert_equal C1.name, rows[0][1]
50
- assert o.__peer.dirty?
52
+ assert !o.__peer.dirty?
51
53
  end
52
54
 
53
55
  def test_save_objects
@@ -89,6 +91,7 @@ module DBI::GenericTests
89
91
  @runtime.create o
90
92
  @runtime.save o
91
93
  rows = @runtime.dbh.select_all 'select * from r_params'
94
+
92
95
  assert_equal 1, rows.size
93
96
  assert_equal o.primary_key, rows[0][P_PK].to_i
94
97
  assert_equal PARAM_FLAG_INT, rows[0][P_FLAGS].to_i
@@ -122,6 +125,7 @@ module DBI::GenericTests
122
125
  for i in 1..10
123
126
  hash[i] = C2.new
124
127
  @runtime.create hash[i]
128
+ @runtime.save hash[i]
125
129
  end
126
130
  o, o.p1 = C1.new, hash
127
131
 
@@ -145,9 +149,11 @@ module DBI::GenericTests
145
149
  hash = {777 => C2.new}
146
150
 
147
151
  @runtime.create hash[777]
152
+ @runtime.save hash[777]
148
153
 
149
154
  hash['key'] = C2.new
150
155
  @runtime.create hash['key']
156
+ @runtime.save hash['key']
151
157
 
152
158
  o, o.p1 = C1.new, hash
153
159
 
@@ -183,6 +189,7 @@ module DBI::GenericTests
183
189
  for i in 0..9
184
190
  o = C2.new
185
191
  @runtime.create o
192
+ @runtime.save o
186
193
  array[i] = o
187
194
  end
188
195
  o, o.p1 = C1.new, array
@@ -211,8 +218,7 @@ module DBI::GenericTests
211
218
  @runtime.create o2
212
219
 
213
220
  o1.p1 = o2
214
- @runtime.save o1
215
- @runtime.save o2
221
+ @runtime.save [o1, o2]
216
222
 
217
223
  assert 1, @runtime.dbh.select_all(
218
224
  'select * from r_objects where object_pk = ?', o1.primary_key).size
@@ -280,7 +286,7 @@ module DBI::GenericTests
280
286
  end
281
287
 
282
288
  def test_param_type_date
283
- pk, date = nil, Date.today
289
+ pk, date = nil, Date.today
284
290
  Rubernate.session {o = C1.new.attach; o.p1 = date; pk = o.primary_key}
285
291
  Rubernate.session {
286
292
  o = find_by_pk pk
@@ -419,8 +425,8 @@ module GenericRuntimeTests
419
425
  include Queries
420
426
  include FixtureClasses
421
427
 
422
- def init rt_class, db_url, db_user, db_password
423
- @factory = Configuration.new rt_class, nil, db_url, db_user, db_password
428
+ def init rt_class, gen, db_url, db_user, db_password
429
+ @factory = Configuration.new rt_class, nil, gen, db_url, db_user, db_password
424
430
  @factory.connect {|dbh|
425
431
  dbh.do 'delete from r_params'
426
432
  dbh.do 'delete from r_objects'
@@ -617,17 +623,76 @@ module GenericRuntimeTests
617
623
  def test_remove_referred
618
624
  pk1, pk2 = nil
619
625
  Rubernate.session do
620
- o1, o2 = C1.new.attach, C1.new.attach
626
+ o1, o2 = C2.new.attach, C1.new.attach
621
627
  pk1, pk2 = o1.primary_key, o2.primary_key
622
- o1.p1 = o2
628
+ o1.p1, o1.p2 = o2, 'initial'
623
629
  end
624
630
  Rubernate.session do
625
631
  o1 = find_by_pk pk1
626
632
  o2 = find_by_pk pk2
633
+ assert_equal 'initial', o1.p2
627
634
  assert_equal o2, o1.p1
635
+ o1.p2 = 'updated'
628
636
  o2.remove!
629
637
  assert o1.p1.removed?
630
638
  end
639
+ Rubernate.session do
640
+ o1 = find_by_pk pk1
641
+ assert_nil o1.p1
642
+ assert_equal 'updated', o1.p2
643
+ end
644
+ end
645
+
646
+ def test_insert_removed
647
+ pk1, pk2 = nil
648
+ Rubernate.session do
649
+ o1, o2 = C1.new.attach, C1.new.attach
650
+ pk1, pk2 = o1.primary_key, o2.primary_key
651
+ end
652
+ Rubernate.session do
653
+ o1 = find_by_pk pk1
654
+ o2 = find_by_pk pk2
655
+ o2.remove!
656
+ o1.p1 = o2
657
+ end
658
+ Rubernate.session do
659
+ o1 = find_by_pk pk1
660
+ assert_nil o1.p1
661
+ end
662
+ end
663
+
664
+ def test_override_removed
665
+ pk1, pk2 = nil
666
+ Rubernate.session do
667
+ o1, o2 = C1.new.attach, C1.new.attach
668
+ pk1, pk2 = o1.primary_key, o2.primary_key
669
+ o1.p1 = o2
670
+ end
671
+ Rubernate.session do
672
+ o1 = find_by_pk pk1
673
+ o2 = find_by_pk pk2
674
+ o2.remove!
675
+ o1.p1 = o1
676
+ end
677
+ Rubernate.session do
678
+ o1 = find_by_pk pk1
679
+ assert_equal o1, o1.p1
680
+ end
681
+ end
682
+
683
+ def test_update_by_removed
684
+ pk1, pk2 = nil
685
+ Rubernate.session do
686
+ o1, o2 = C1.new.attach, C1.new.attach
687
+ pk1, pk2 = o1.primary_key, o2.primary_key
688
+ o1.p1 = 'initial'
689
+ end
690
+ Rubernate.session do
691
+ o1 = find_by_pk pk1
692
+ o2 = find_by_pk pk2
693
+ o2.remove!
694
+ o1.p1 = o2
695
+ end
631
696
  Rubernate.session do
632
697
  o1 = find_by_pk pk1
633
698
  assert_nil o1.p1
@@ -750,5 +815,41 @@ module GenericRuntimeTests
750
815
  assert o1.p2[2].__peer.is_a?(Peer)
751
816
  end
752
817
  end
818
+
819
+ def test_find_virtual
820
+ Rubernate.session do
821
+ o = C1.new.attach
822
+ assert_equal o, find_by_pk(o.primary_key)
823
+ end
824
+
825
+ Rubernate.session do
826
+ o = C1.new.attach
827
+ assert_equal o, find_by_query('Select :o; Where o.pk == :pk', :pk => o.primary_key)[0]
828
+ end
829
+ end
830
+
831
+ def test_remove_virtual
832
+ pk = nil
833
+ Rubernate.session do
834
+ o = C1.new.attach
835
+ pk = o.primary_key
836
+ o.remove!
837
+ end
838
+ Rubernate.session do
839
+ assert_raise(ObjectNotFoundException) {find_by_pk pk}
840
+ end
841
+ end
842
+
843
+ def test_pk_gen
844
+ return unless PKGenerator.chunk_factory
845
+ gen = PKGenerator.instance
846
+ Rubernate.session do
847
+ pk = gen.generate dbh
848
+ 51.times do
849
+ old, pk = pk, gen.generate(dbh)
850
+ assert_equal old + 1, pk
851
+ end
852
+ end
853
+ end
753
854
  end
754
855
  end
@@ -7,13 +7,13 @@ require 'rubernate/impl/dbi_generic_stub'
7
7
  class Rubernate::DBI::MysqlTest < Test::Unit::TestCase
8
8
  include Rubernate::DBI::GenericTests
9
9
  def setup
10
- init MYSQL_RUNTIME_CLASS, MYSQL_DB_URL, MYSQL_DB_USER, MYSQL_DB_PWD
10
+ init MYSQL_RUNTIME_CLASS, nil, MYSQL_DB_URL, MYSQL_DB_USER, MYSQL_DB_PWD
11
11
  end
12
12
  end
13
13
 
14
14
  class Rubernate::DBI::MysqlRuntimeTest < Test::Unit::TestCase
15
15
  include Rubernate::GenericRuntimeTests
16
16
  def setup
17
- init MYSQL_RUNTIME_CLASS, MYSQL_DB_URL, MYSQL_DB_USER, MYSQL_DB_PWD
17
+ init MYSQL_RUNTIME_CLASS, nil, MYSQL_DB_URL, MYSQL_DB_USER, MYSQL_DB_PWD
18
18
  end
19
19
  end
@@ -10,7 +10,7 @@ module DBI
10
10
  class OracleTest < Test::Unit::TestCase
11
11
  include Rubernate::DBI::GenericTests
12
12
  def setup
13
- init ORA_RUNTIME_CLASS, ORA_DB_URL, ORA_DB_USER, ORA_DB_PWD
13
+ init ORA_RUNTIME_CLASS, OraPKChunkFactory.new, ORA_DB_URL, ORA_DB_USER, ORA_DB_PWD
14
14
  end
15
15
  =begin
16
16
  # This methods test bug appers when we try
@@ -37,7 +37,7 @@ module DBI
37
37
  class OracleRuntimeTest < Test::Unit::TestCase
38
38
  include Rubernate::GenericRuntimeTests
39
39
  def setup
40
- init ORA_RUNTIME_CLASS, ORA_DB_URL, ORA_DB_USER, ORA_DB_PWD
40
+ init ORA_RUNTIME_CLASS, OraPKChunkFactory.new, ORA_DB_URL, ORA_DB_USER, ORA_DB_PWD
41
41
  end
42
42
  end
43
43
  end
@@ -9,14 +9,14 @@ module DBI
9
9
  class PgTest < Test::Unit::TestCase
10
10
  include Rubernate::DBI::GenericTests
11
11
  def setup
12
- init PG_RUNTIME_CLASS, PG_DB_URL, PG_DB_USER, PG_DB_PWD
12
+ init PG_RUNTIME_CLASS, PgPKChunkFactory.new, PG_DB_URL, PG_DB_USER, PG_DB_PWD
13
13
  end
14
14
  end
15
15
 
16
16
  class PgRuntimeTest < Test::Unit::TestCase
17
17
  include Rubernate::GenericRuntimeTests
18
18
  def setup
19
- init PG_RUNTIME_CLASS, PG_DB_URL, PG_DB_USER, PG_DB_PWD
19
+ init PG_RUNTIME_CLASS, PgPKChunkFactory.new, PG_DB_URL, PG_DB_USER, PG_DB_PWD
20
20
  end
21
21
  end
22
22
  end
@@ -264,6 +264,23 @@ module Rubernate
264
264
  assert_not_nil a.recall
265
265
  assert_equal 4, a[1]
266
266
  end
267
+
268
+ def test_change_track
269
+ peer = Peer.new
270
+ peer[:p1] = 'new'
271
+ assert_equal({:p1 => :inserted}, peer.change_track)
272
+ peer.dirty = false
273
+ peer[:p2] = ["new_element"]
274
+ assert_equal({:p2 => :inserted}, peer.change_track)
275
+ peer.dirty = false
276
+ peer[:p1] = 'updated'
277
+ peer[:p2] << 'array_updated'
278
+ assert_equal({:p1 => :modified, :p2 => :modified}, peer.change_track)
279
+ peer.dirty = false
280
+ peer[:p1] = nil
281
+ peer[:p2] = nil
282
+ assert_equal({:p1 => :modified, :p2 => :modified}, peer.change_track)
283
+ end
267
284
  end
268
285
 
269
286
  class Rubernate::BaseRuntimeTest < Test::Unit::TestCase
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.6
7
- date: 2006-03-30 00:00:00 +04:00
6
+ version: 0.1.7
7
+ date: 2006-05-23 00:00:00 +04:00
8
8
  summary: Object-oriented storage for Ruby objects based on relational database model
9
9
  require_paths:
10
10
  - lib
@@ -40,6 +40,7 @@ files:
40
40
  - lib/rubernate/queries.rb
41
41
  - lib/rubernate/runtime.rb
42
42
  - lib/rubernate/impl/dbi_generic.rb
43
+ - lib/rubernate/impl/dbi_genpk.rb
43
44
  - lib/rubernate/impl/dbi_mysql.rb
44
45
  - lib/rubernate/impl/dbi_oracle.rb
45
46
  - lib/rubernate/impl/dbi_pg.rb