flexirecord 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +31 -10
- data/lib/flexirecord.rb +116 -107
- 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
|
-
-
|
6
|
-
|
7
|
-
|
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
|
-
-
|
11
|
-
|
12
|
-
|
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
|
210
|
-
@
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
-
|
271
|
-
@
|
272
|
-
|
273
|
-
|
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
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
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
|
-
|
312
|
-
|
313
|
-
|
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
|
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
|
-
|
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
|
-
|
1496
|
+
transaction(:read_committed) do
|
1486
1497
|
self.class.lock(:share_row_exclusive)
|
1487
|
-
|
1498
|
+
db_result = nil
|
1499
|
+
if self.position == :first
|
1488
1500
|
db_result = self.class.db_query1(
|
1489
|
-
'SELECT
|
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
|
1506
|
+
'SELECT "position" + 1 AS "result" ' <<
|
1494
1507
|
'FROM ' << self.class.table << ' WHERE "position" NOTNULL ORDER BY "position" DESC')
|
1495
|
-
|
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.
|
7
|
-
date: 2007-02-
|
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/
|