flexirecord 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/CHANGELOG +31 -10
  2. data/lib/flexirecord.rb +116 -107
  3. metadata +2 -2
data/CHANGELOG CHANGED
@@ -1,15 +1,36 @@
1
+ %YAML 1.1
2
+ ---
1
3
 
2
- CHANGELOG for FlexiRecord:
4
+ # CHANGELOG for FlexiRecord:
3
5
 
4
- 2007-02-10:
5
- - Changed the order of arguments passed to FlexiRecord::Reference#combine to match the documentation and renamed the method to FlexiRecord::Reference#connect.
6
- - Minor bugfix in FlexiRecord::Relationship#new
7
- - Added FlexiRecord::BaseRecord.add_connected_references as a more simple way to add many-to-many relations.
6
+ - 2007-02-10:
7
+ - >
8
+ Changed the order of arguments passed to FlexiRecord::Reference#combine
9
+ to match the documentation and renamed the method to
10
+ FlexiRecord::Reference#connect.
11
+ - >
12
+ Minor bugfix in FlexiRecord::Relationship#new
13
+ - >
14
+ Added FlexiRecord::BaseRecord.add_connected_references as a more simple
15
+ way to add many-to-many relations.
8
16
 
9
- 2007-02-11:
10
- - Renamed the word 'column' to 'attr' or 'attribute' at several places in the code and documentation.
11
- - Freezed record arrays, which are fetched through attributes for many-to-one or many-to-many relations.
12
- - Added a lock method, to lock tables in a nicier way.
17
+ - 2007-02-11:
18
+ - >
19
+ Renamed the word 'column' to 'attr' or 'attribute' at several places in
20
+ the code and documentation.
21
+ - >
22
+ Freezed record arrays, which are fetched through attributes for
23
+ many-to-one or many-to-many relations.
24
+ - >
25
+ Added a lock method, to lock tables in a nicier way.
13
26
 
14
- Release of version 0.0.4.
27
+ - Release of version 0.0.4.
28
+
29
+ - 2007-02-11:
30
+ - >
31
+ Added FlexiRecord::BaseRecord#transaction method.
32
+ - >
33
+ Fixed a bug in the FlexiRecord::ListRecord module.
34
+ - >
35
+ 'src_to_dst_attr' and 'dst_to_src_attr' arguments of FlexiRecord::Reference.new are now allowed to be nil.
15
36
 
data/lib/flexirecord.rb CHANGED
@@ -123,7 +123,7 @@ module FlexiRecord
123
123
  # - LockMode::Share
124
124
  # (Prohibits data changes in the table.)
125
125
  # - LockMode::ShareRowExclusive
126
- # (Prohibits data changes and other Share or ShareRowExclusive locks. Used instead of LockMode::Share to prohibit dead locks.)
126
+ # (Prohibits data changes and other Share or ShareRowExclusive locks. Used instead of LockMode::Share to prohibit dead locks, where two processes holding share locks want to write to a table.)
127
127
  # - LockMode::Exclusive
128
128
  # (Prohibits anything else than reading from the table.)
129
129
  # - LockMode::AccessExclusive
@@ -178,7 +178,7 @@ module FlexiRecord
178
178
 
179
179
  # Returns a new reference object, describing a relation where objects of the 'source_class' refer to objects of the 'destination_class'. The 'column_info' field describes the columns used for that reference. If the 'column_info' field is a string, the primary key is used in the destination class, and the primary key prefixed by the string given in 'column_info' is used as the foreign key in the source class. If 'column_info' is an array, it contains the columns in the source class, followed by the columns in the destination class. The field 'src_to_dst_attr' contains the name of the attribute in the source class, which is referring to one object of the destination class. The field 'dst_to_src_attr' contains the name of the attribute in the destination class, which is referring to one or many objects of the source class. After the reference has been created, reader, loader and setter functions are added to the 'source_class' and 'destination_class', to provide access to referenced and referring objects.
180
180
  # This method is private, use one of the child classes OneToOneReference or ManyToOneReference, which get the same arguments, to generate references of a given type.
181
- def initialize(source_class, destination_class, column_info, src_to_dst_attr, dst_to_src_attr)
181
+ def initialize(source_class, destination_class, column_info, src_to_dst_attr, dst_to_src_attr=nil)
182
182
  unless source_class.kind_of? Class and destination_class.kind_of? Class
183
183
  raise TypeError, "Class expected"
184
184
  end
@@ -204,113 +204,119 @@ module FlexiRecord
204
204
  end
205
205
  @source_columns.freeze
206
206
  @destination_columns.freeze
207
- @src_to_dst_attr = src_to_dst_attr.to_s.dup.freeze
208
- @dst_to_src_attr = dst_to_src_attr.to_s.dup.freeze
209
- # Work at the source class:
210
- @source_class.set_loader(@src_to_dst_attr) do |source_records, arguments|
211
- unless arguments.empty?
212
- raise ArgumentError, "No extra arguments may be specified for outgoing reference columns."
213
- end
214
- destination_records = @destination_class.select_by_value_set(
215
- @destination_columns,
216
- source_records.collect { |source_record|
217
- @source_columns.collect { |column| source_record[column] }
218
- },
219
- *arguments
220
- )
221
- destination_record_hash = {}
222
- destination_records.each do |destination_record|
223
- destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
224
- if self.one_to_one?
225
- destination_record[@dst_to_src_attr] = nil
226
- end
227
- end
228
- source_records.each do |source_record|
229
- destination_record =
230
- destination_record_hash[@source_columns.collect { |column| source_record[column] }]
231
- source_record[@src_to_dst_attr, *arguments] = destination_record
232
- if destination_record and self.one_to_one?
233
- destination_record[@dst_to_src_attr] = source_record
207
+ @src_to_dst_attr = src_to_dst_attr ? src_to_dst_attr.to_s.dup.freeze : nil
208
+ @dst_to_src_attr = dst_to_src_attr ? dst_to_src_attr.to_s.dup.freeze : nil
209
+ # Work at the source_class:
210
+ if @src_to_dst_attr
211
+ @source_class.set_loader(@src_to_dst_attr) do |source_records, arguments|
212
+ unless arguments.empty?
213
+ raise ArgumentError, "No extra arguments may be specified for outgoing reference columns."
234
214
  end
235
- end
236
- next destination_records
237
- end
238
- @source_columns.each_index do |column_index|
239
- source_column = @source_columns[column_index]
240
- destination_column = @destination_columns[column_index]
241
- @source_class.set_reader(source_column) do |source_record, arguments|
242
- destination_record = source_record[@src_to_dst_attr]
243
- next destination_record ? destination_record[destination_column] : source_record[source_column]
244
- end
245
- @source_class.set_setter(source_column) do |source_record, value|
246
- source_record.delete_from_cache(@src_to_dst_attr)
247
- source_record[source_column] = value
248
- end
249
- end
250
- if self.one_to_one?
251
- @source_class.set_setter(@src_to_dst_attr) do |source_record, value|
252
- old_destination_record = source_record[@src_to_dst_attr]
253
- if old_destination_record
254
- old_destination_record[@dst_to_src_attr] = nil
215
+ destination_records = @destination_class.select_by_value_set(
216
+ @destination_columns,
217
+ source_records.collect { |source_record|
218
+ @source_columns.collect { |column| source_record[column] }
219
+ },
220
+ *arguments
221
+ )
222
+ destination_record_hash = {}
223
+ destination_records.each do |destination_record|
224
+ destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
225
+ if self.one_to_one? and @dst_to_src_attr
226
+ destination_record[@dst_to_src_attr] = nil
227
+ end
255
228
  end
256
- source_record[@src_to_dst_attr] = value
257
- if value
258
- value[@dst_to_src_attr] = source_record
229
+ source_records.each do |source_record|
230
+ destination_record =
231
+ destination_record_hash[@source_columns.collect { |column| source_record[column] }]
232
+ source_record[@src_to_dst_attr, *arguments] = destination_record
233
+ if destination_record and self.one_to_one? and @dst_to_src_attr
234
+ destination_record[@dst_to_src_attr] = source_record
235
+ end
259
236
  end
237
+ next destination_records
260
238
  end
261
- end
262
- # Work at the destination class:
263
- @destination_class.set_loader(@dst_to_src_attr) do |destination_records, arguments|
264
- unless arguments.empty?
265
- unless arguments[0].respond_to? :to_str
266
- raise "First argument of reader method is not a SQL snippet string."
239
+ @source_columns.each_index do |column_index|
240
+ source_column = @source_columns[column_index]
241
+ destination_column = @destination_columns[column_index]
242
+ @source_class.set_reader(source_column) do |source_record, arguments|
243
+ destination_record = source_record[@src_to_dst_attr]
244
+ next destination_record ? destination_record[destination_column] : source_record[source_column]
245
+ end
246
+ @source_class.set_setter(source_column) do |source_record, value|
247
+ source_record.delete_from_cache(@src_to_dst_attr)
248
+ source_record[source_column] = value
267
249
  end
268
- arguments[0] = arguments[0].to_str
269
250
  end
270
- source_records = @source_class.select_by_value_set(
271
- @source_columns,
272
- destination_records.collect { |destination_record|
273
- @destination_columns.collect { |column| destination_record[column] }
274
- },
275
- *arguments
276
- )
277
- destination_record_hash = {}
278
- destination_records.each do |destination_record|
279
- destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
280
- destination_record[@dst_to_src_attr, *arguments] =
281
- if self.many_to_one?
282
- FlexiRecord::RecordArray.new(@source_class)
283
- else
284
- nil
251
+ if self.one_to_one? and @dst_to_src_attr
252
+ @source_class.set_setter(@src_to_dst_attr) do |source_record, value|
253
+ old_destination_record = source_record[@src_to_dst_attr]
254
+ if old_destination_record
255
+ old_destination_record[@dst_to_src_attr] = nil
285
256
  end
286
- end
287
- source_records.each do |source_record|
288
- destination_record = destination_record_hash[@source_columns.collect { |column| source_record[column] }]
289
- source_record[@src_to_dst_attr] = destination_record
290
- if destination_record
291
- if self.many_to_one?
292
- destination_record[@dst_to_src_attr, *arguments] << source_record
293
- else
294
- destination_record[@dst_to_src_attr, *arguments] = source_record
257
+ source_record[@src_to_dst_attr] = value
258
+ if value
259
+ value[@dst_to_src_attr] = source_record
295
260
  end
296
261
  end
297
262
  end
298
- if self.many_to_one?
263
+ end
264
+ # Work at the destination_class:
265
+ if @dst_to_src_attr
266
+ @destination_class.set_loader(@dst_to_src_attr) do |destination_records, arguments|
267
+ unless arguments.empty?
268
+ unless arguments[0].respond_to? :to_str
269
+ raise "First argument of reader method is not a SQL snippet string."
270
+ end
271
+ arguments[0] = arguments[0].to_str
272
+ end
273
+ source_records = @source_class.select_by_value_set(
274
+ @source_columns,
275
+ destination_records.collect { |destination_record|
276
+ @destination_columns.collect { |column| destination_record[column] }
277
+ },
278
+ *arguments
279
+ )
280
+ destination_record_hash = {}
299
281
  destination_records.each do |destination_record|
300
- destination_record[@dst_to_src_attr, *arguments].freeze
282
+ destination_record_hash[@destination_columns.collect { |column| destination_record[column] }] = destination_record
283
+ destination_record[@dst_to_src_attr, *arguments] =
284
+ if self.many_to_one?
285
+ FlexiRecord::RecordArray.new(@source_class)
286
+ else
287
+ nil
288
+ end
301
289
  end
302
- end
303
- next source_records
304
- end
305
- if self.one_to_one?
306
- @destination_class.set_setter(@dst_to_src_attr) do |destination_record, value|
307
- old_source_record = destination_record[@dst_to_src_attr]
308
- if old_source_record
309
- old_source_record[@src_to_dst_attr] = nil
290
+ source_records.each do |source_record|
291
+ destination_record = destination_record_hash[@source_columns.collect { |column| source_record[column] }]
292
+ if @src_to_dst_attr
293
+ source_record[@src_to_dst_attr] = destination_record
294
+ end
295
+ if destination_record
296
+ if self.many_to_one?
297
+ destination_record[@dst_to_src_attr, *arguments] << source_record
298
+ else
299
+ destination_record[@dst_to_src_attr, *arguments] = source_record
300
+ end
301
+ end
302
+ end
303
+ if self.many_to_one?
304
+ destination_records.each do |destination_record|
305
+ destination_record[@dst_to_src_attr, *arguments].freeze
306
+ end
310
307
  end
311
- destination_record[@dst_to_src_attr] = value
312
- if value
313
- value[@src_to_dst_attr] = destination_record
308
+ next source_records
309
+ end
310
+ if self.one_to_one? and @src_to_dst_attr
311
+ @destination_class.set_setter(@dst_to_src_attr) do |destination_record, value|
312
+ old_source_record = destination_record[@dst_to_src_attr]
313
+ if old_source_record
314
+ old_source_record[@src_to_dst_attr] = nil
315
+ end
316
+ destination_record[@dst_to_src_attr] = value
317
+ if value
318
+ value[@src_to_dst_attr] = destination_record
319
+ end
314
320
  end
315
321
  end
316
322
  end
@@ -352,7 +358,7 @@ module FlexiRecord
352
358
  end
353
359
  sql_snippet = sql_snippet.to_str
354
360
  end
355
- # TODO: Do SELECT DISTINCT. (breaks for now, as ORDER BY expressions must appear in select list)
361
+ # TODO: Do SELECT DISTINCT perhaps? (breaks for now, as ORDER BY expressions must appear in select list)
356
362
  destination_records = unless source_records.empty?
357
363
  destination_class.sql(
358
364
  'SELECT ' << FlexiRecord::DefaultTableAlias << '.* FROM (' <<
@@ -1152,6 +1158,11 @@ module FlexiRecord
1152
1158
  end
1153
1159
  end
1154
1160
 
1161
+ # Wraps the given block in a transaction of the database being used to store the object. See FlexiRecord::Connection#transaction for details of the command. This object is automatically passed to the FlexiRecord::Connection#transaction method, to rollback changes, in case an Error is raised.
1162
+ def transaction(*arguments, &block)
1163
+ self.class.transaction(self, *arguments, &block)
1164
+ end
1165
+
1155
1166
  public # end of methods of BaseRecord
1156
1167
 
1157
1168
  end # end of class BaseRecord
@@ -1174,7 +1185,7 @@ module FlexiRecord
1174
1185
  # Instead of UPDATEing or INSERTing a value, depending on the state of the object, it is always replaced in the database. When the special attribute 'void' is set, the record will be destroyed instead of saved.
1175
1186
  def save
1176
1187
  # TODO: improve efficiency, when a "REPLACE" command is available in PostgreSQL
1177
- self.class.transaction(self, :read_committed) do
1188
+ transaction(:read_committed) do
1178
1189
  self.class.lock(:share_row_exclusive)
1179
1190
  @saved =
1180
1191
  self.class.select_by_value_set(self.class.primary_columns, [self.class.primary_columns.collect { |column| self.read(column) }]).length > 0
@@ -1482,21 +1493,19 @@ module FlexiRecord
1482
1493
  module ListRecord
1483
1494
 
1484
1495
  def save
1485
- self.class.transaction(self, :read_committed) do
1496
+ transaction(:read_committed) do
1486
1497
  self.class.lock(:share_row_exclusive)
1487
- if self.position == :first
1498
+ db_result = nil
1499
+ if self.position == :first
1488
1500
  db_result = self.class.db_query1(
1489
- 'SELECT COALESCE("position" - 1, 0) AS "result" ' <<
1501
+ 'SELECT "position" - 1 AS "result" ' <<
1490
1502
  'FROM ' << self.class.table << ' WHERE "position" NOTNULL ORDER BY "position" ASC)')
1503
+ self.position = db_result ? db_result.result : 0
1491
1504
  elsif self.position == :last
1492
1505
  db_result = self.class.db_query1(
1493
- 'SELECT COALESCE("position" + 1, 0) AS "result" ' <<
1506
+ 'SELECT "position" + 1 AS "result" ' <<
1494
1507
  'FROM ' << self.class.table << ' WHERE "position" NOTNULL ORDER BY "position" DESC')
1495
- end
1496
- if db_result
1497
- self.position = db_result.result
1498
- else
1499
- self.position = 0
1508
+ self.position = db_result ? db_result.result : 0
1500
1509
  end
1501
1510
  return super
1502
1511
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: flexirecord
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.4
7
- date: 2007-02-11 00:00:00 +00:00
6
+ version: 0.0.5
7
+ date: 2007-02-13 00:00:00 +00:00
8
8
  summary: Object-Oriented Database Access Library
9
9
  require_paths:
10
10
  - lib/