lafcadio 0.9.0 → 0.9.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/lib/lafcadio.rb +1 -1
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/domain.rb +363 -255
- data/lib/lafcadio/domain.rb~ +201 -230
- data/lib/lafcadio/mock.rb +64 -70
- data/lib/lafcadio/mock.rb~ +48 -49
- data/lib/lafcadio/objectField.rb +137 -127
- data/lib/lafcadio/objectField.rb~ +7 -7
- data/lib/lafcadio/objectStore.rb +560 -586
- data/lib/lafcadio/objectStore.rb~ +495 -536
- data/lib/lafcadio/query.rb +320 -213
- data/lib/lafcadio/query.rb~ +129 -131
- data/lib/lafcadio/schema.rb +10 -14
- data/lib/lafcadio/schema.rb~ +1 -1
- data/lib/lafcadio/test.rb +174 -75
- data/lib/lafcadio/test.rb~ +191 -0
- data/lib/lafcadio/util.rb +1 -32
- data/lib/lafcadio/util.rb~ +1 -6
- metadata +2 -2
@@ -5,227 +5,7 @@ require 'lafcadio/query'
|
|
5
5
|
require 'lafcadio/util'
|
6
6
|
|
7
7
|
module Lafcadio
|
8
|
-
class Committer #:nodoc:
|
9
|
-
INSERT = 1
|
10
|
-
UPDATE = 2
|
11
|
-
DELETE = 3
|
12
|
-
|
13
|
-
attr_reader :commit_type, :db_object
|
14
|
-
|
15
|
-
def initialize(db_object, dbBridge, cache)
|
16
|
-
@db_object = db_object
|
17
|
-
@dbBridge = dbBridge
|
18
|
-
@cache = cache
|
19
|
-
@objectStore = ObjectStore.get_object_store
|
20
|
-
@commit_type = nil
|
21
|
-
end
|
22
|
-
|
23
|
-
def execute
|
24
|
-
@db_object.verify if LafcadioConfig.new()['checkFields'] == 'onCommit'
|
25
|
-
set_commit_type
|
26
|
-
@db_object.last_commit = get_last_commit
|
27
|
-
@db_object.pre_commit_trigger
|
28
|
-
update_dependent_domain_objects if @db_object.delete
|
29
|
-
@dbBridge.commit @db_object
|
30
|
-
unless @db_object.pk_id
|
31
|
-
@db_object.pk_id = @dbBridge.last_pk_id_inserted
|
32
|
-
end
|
33
|
-
@cache.update_after_commit self
|
34
|
-
@db_object.post_commit_trigger
|
35
|
-
end
|
36
|
-
|
37
|
-
def get_last_commit
|
38
|
-
if @db_object.delete
|
39
|
-
DomainObject::COMMIT_DELETE
|
40
|
-
elsif @db_object.pk_id
|
41
|
-
DomainObject::COMMIT_EDIT
|
42
|
-
else
|
43
|
-
DomainObject::COMMIT_ADD
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def set_commit_type
|
48
|
-
if @db_object.delete
|
49
|
-
@commit_type = DELETE
|
50
|
-
elsif @db_object.pk_id
|
51
|
-
@commit_type = UPDATE
|
52
|
-
else
|
53
|
-
@commit_type = INSERT
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def update_dependent_domain_objects
|
58
|
-
dependent_classes = @db_object.domain_class.dependent_classes
|
59
|
-
dependent_classes.keys.each { |aClass|
|
60
|
-
field = dependent_classes[aClass]
|
61
|
-
collection = @objectStore.get_filtered( aClass.name, @db_object,
|
62
|
-
field.name )
|
63
|
-
collection.each { |dependentObject|
|
64
|
-
if field.delete_cascade
|
65
|
-
dependentObject.delete = true
|
66
|
-
else
|
67
|
-
dependentObject.send( field.name + '=', nil )
|
68
|
-
end
|
69
|
-
@objectStore.commit(dependentObject)
|
70
|
-
}
|
71
|
-
}
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class CouldntMatchDomainClassError < RuntimeError #:nodoc:
|
76
|
-
end
|
77
|
-
|
78
|
-
class DbBridge #:nodoc:
|
79
|
-
@@last_pk_id_inserted = nil
|
80
|
-
|
81
|
-
def self._load(aString)
|
82
|
-
aString =~ /db_conn:/
|
83
|
-
db_conn_str = $'
|
84
|
-
begin
|
85
|
-
db_conn = Marshal.load db_conn_str
|
86
|
-
rescue TypeError
|
87
|
-
db_conn = nil
|
88
|
-
end
|
89
|
-
DbConnection.set_db_connection db_conn
|
90
|
-
new
|
91
|
-
end
|
92
|
-
|
93
|
-
def initialize
|
94
|
-
@db_conn = DbConnection.get_db_connection
|
95
|
-
ObjectSpace.define_finalizer( self, proc { |id|
|
96
|
-
DbConnection.get_db_connection.disconnect
|
97
|
-
} )
|
98
|
-
end
|
99
|
-
|
100
|
-
def _dump(aDepth)
|
101
|
-
dbDump = @dbh.respond_to?( '_dump' ) ? @dbh._dump : @dbh.class.to_s
|
102
|
-
"dbh:#{dbDump}"
|
103
|
-
end
|
104
|
-
|
105
|
-
def commit(db_object)
|
106
|
-
sqlMaker = DomainObjectSqlMaker.new(db_object)
|
107
|
-
sqlMaker.sql_statements.each { |sql, binds| execute_commit( sql, binds ) }
|
108
|
-
if sqlMaker.sql_statements[0].first =~ /insert/
|
109
|
-
sql = 'select last_insert_id()'
|
110
|
-
result = execute_select( sql )
|
111
|
-
@@last_pk_id_inserted = result[0]['last_insert_id()'].to_i
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def execute_commit( sql, binds ); @db_conn.do( sql, *binds ); end
|
116
|
-
|
117
|
-
def execute_select(sql)
|
118
|
-
maybe_log sql
|
119
|
-
begin
|
120
|
-
@db_conn.select_all( sql )
|
121
|
-
rescue DBI::DatabaseError => e
|
122
|
-
raise $!.to_s + ": #{ e.errstr }"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def get_collection_by_query(query)
|
127
|
-
domain_class = query.domain_class
|
128
|
-
execute_select( query.to_sql ).collect { |row_hash|
|
129
|
-
domain_class.new( SqlValueConverter.new( domain_class, row_hash ) )
|
130
|
-
}
|
131
|
-
end
|
132
|
-
|
133
|
-
def group_query( query )
|
134
|
-
execute_select( query.to_sql ).map { |row| query.result_row( row ) }
|
135
|
-
end
|
136
|
-
|
137
|
-
def last_pk_id_inserted; @@last_pk_id_inserted; end
|
138
|
-
|
139
|
-
def maybe_log(sql)
|
140
|
-
config = LafcadioConfig.new
|
141
|
-
if config['logSql'] == 'y'
|
142
|
-
sqllog = Log4r::Logger['sql'] || Log4r::Logger.new( 'sql' )
|
143
|
-
filename = File.join( config['logdir'], config['sqlLogFile'] || 'sql' )
|
144
|
-
outputter = Log4r::FileOutputter.new( 'outputter',
|
145
|
-
{ :filename => filename } )
|
146
|
-
sqllog.outputters = outputter
|
147
|
-
sqllog.info sql
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def transaction( action )
|
152
|
-
tr = Transaction.new @db_conn
|
153
|
-
tr.commit
|
154
|
-
begin
|
155
|
-
action.call tr
|
156
|
-
tr.commit
|
157
|
-
rescue RollbackError
|
158
|
-
# rollback handled by Transaction
|
159
|
-
rescue
|
160
|
-
err_to_raise = $!
|
161
|
-
tr.rollback false
|
162
|
-
raise err_to_raise
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
class Transaction
|
167
|
-
def initialize( db_conn ); @db_conn = db_conn; end
|
168
|
-
|
169
|
-
def commit; @db_conn.commit; end
|
170
|
-
|
171
|
-
def rollback( raise_error = true )
|
172
|
-
@db_conn.rollback
|
173
|
-
raise RollbackError if raise_error
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
class RollbackError < StandardError; end
|
178
|
-
end
|
179
|
-
|
180
|
-
class DbConnection < ContextualService::Service
|
181
|
-
@@connectionClass = DBI
|
182
|
-
@@db_name = nil
|
183
|
-
@@dbh = nil
|
184
|
-
|
185
|
-
def self.flush
|
186
|
-
DbConnection.set_db_connection( nil )
|
187
|
-
@@dbh = nil
|
188
|
-
end
|
189
|
-
|
190
|
-
def self.set_connection_class( aClass ); @@connectionClass = aClass; end
|
191
|
-
|
192
|
-
def self.set_db_name( db_name ); @@db_name = db_name; end
|
193
|
-
|
194
|
-
def self.set_dbh( dbh ); @@dbh = dbh; end
|
195
|
-
|
196
|
-
def initialize
|
197
|
-
@@dbh = load_new_dbh if @@dbh.nil?
|
198
|
-
@dbh = @@dbh
|
199
|
-
end
|
200
|
-
|
201
|
-
def disconnect; @dbh.disconnect if @dbh; end
|
202
|
-
|
203
|
-
def load_new_dbh
|
204
|
-
config = LafcadioConfig.new
|
205
|
-
dbName = @@db_name || config['dbname']
|
206
|
-
dbAndHost = nil
|
207
|
-
if dbName && config['dbhost']
|
208
|
-
dbAndHost = "dbi:Mysql:#{ dbName }:#{ config['dbhost'] }"
|
209
|
-
else
|
210
|
-
dbAndHost = "dbi:#{config['dbconn']}"
|
211
|
-
end
|
212
|
-
@@dbh = @@connectionClass.connect( dbAndHost, config['dbuser'],
|
213
|
-
config['dbpassword'] )
|
214
|
-
@@dbh['AutoCommit'] = false
|
215
|
-
@@dbh
|
216
|
-
end
|
217
|
-
|
218
|
-
def method_missing( symbol, *args )
|
219
|
-
@dbh.send( symbol, *args )
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
8
|
class DomainObjectInitError < RuntimeError #:nodoc:
|
224
|
-
attr_reader :messages
|
225
|
-
|
226
|
-
def initialize(messages)
|
227
|
-
@messages = messages
|
228
|
-
end
|
229
9
|
end
|
230
10
|
|
231
11
|
class DomainObjectNotFoundError < RuntimeError #:nodoc:
|
@@ -247,122 +27,43 @@ module Lafcadio
|
|
247
27
|
|
248
28
|
attr_accessor :domain_class, :pk_id
|
249
29
|
|
250
|
-
def initialize(
|
251
|
-
if
|
252
|
-
@domain_class =
|
253
|
-
@pk_id =
|
254
|
-
elsif
|
255
|
-
@db_object = domain_classOrDbObject
|
30
|
+
def initialize( *args )
|
31
|
+
if args.size == 2
|
32
|
+
@domain_class = args.first
|
33
|
+
@pk_id = args.last
|
34
|
+
elsif args.first.is_a?( DomainObject )
|
256
35
|
@d_obj_retrieve_time = Time.now
|
257
|
-
@domain_class =
|
258
|
-
@pk_id =
|
36
|
+
@domain_class = args.first.class
|
37
|
+
@pk_id = args.first.pk_id
|
259
38
|
else
|
260
39
|
raise ArgumentError
|
261
40
|
end
|
262
|
-
@db_object = nil
|
263
41
|
end
|
264
42
|
|
265
|
-
def
|
266
|
-
object_store = ObjectStore.get_object_store
|
43
|
+
def db_object
|
267
44
|
if @db_object.nil? || needs_refresh?
|
268
|
-
@db_object =
|
45
|
+
@db_object = ObjectStore.get_object_store.get( @domain_class, @pk_id )
|
269
46
|
@d_obj_retrieve_time = Time.now
|
270
47
|
end
|
271
48
|
@db_object
|
272
49
|
end
|
273
50
|
|
274
51
|
def hash
|
275
|
-
|
52
|
+
db_object.hash
|
276
53
|
end
|
277
54
|
|
278
|
-
def method_missing(methodId, *args)
|
279
|
-
|
55
|
+
def method_missing( methodId, *args )
|
56
|
+
db_object.send( methodId, *args )
|
280
57
|
end
|
281
58
|
|
282
59
|
def needs_refresh?
|
283
60
|
object_store = ObjectStore.get_object_store
|
284
61
|
last_commit_time = object_store.last_commit_time( @domain_class, @pk_id )
|
285
|
-
|
62
|
+
last_commit_time && last_commit_time > @d_obj_retrieve_time
|
286
63
|
end
|
287
64
|
|
288
65
|
def to_s
|
289
|
-
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
class DomainObjectSqlMaker #:nodoc:
|
294
|
-
attr_reader :bind_values
|
295
|
-
|
296
|
-
def initialize(obj); @obj = obj; end
|
297
|
-
|
298
|
-
def delete_sql( domain_class )
|
299
|
-
"delete from #{ domain_class.table_name} " +
|
300
|
-
"where #{ domain_class.sql_primary_key_name }=#{ @obj.pk_id }"
|
301
|
-
end
|
302
|
-
|
303
|
-
def get_name_value_pairs( domain_class )
|
304
|
-
nameValues = []
|
305
|
-
domain_class.class_fields.each { |field|
|
306
|
-
unless field.instance_of?( PrimaryKeyField )
|
307
|
-
value = @obj.send(field.name)
|
308
|
-
unless field.db_will_automatically_write
|
309
|
-
nameValues << field.name_for_sql
|
310
|
-
nameValues <<(field.value_for_sql(value))
|
311
|
-
end
|
312
|
-
if field.bind_write?
|
313
|
-
@bind_values << value
|
314
|
-
end
|
315
|
-
end
|
316
|
-
}
|
317
|
-
QueueHash.new( *nameValues )
|
318
|
-
end
|
319
|
-
|
320
|
-
def insert_sql( domain_class )
|
321
|
-
fields = domain_class.class_fields
|
322
|
-
nameValuePairs = get_name_value_pairs( domain_class )
|
323
|
-
if domain_class.is_based_on?
|
324
|
-
nameValuePairs[domain_class.sql_primary_key_name] = 'LAST_INSERT_ID()'
|
325
|
-
end
|
326
|
-
fieldNameStr = nameValuePairs.keys.join ", "
|
327
|
-
fieldValueStr = nameValuePairs.values.join ", "
|
328
|
-
"insert into #{ domain_class.table_name}(#{fieldNameStr}) " +
|
329
|
-
"values(#{fieldValueStr})"
|
330
|
-
end
|
331
|
-
|
332
|
-
def sql_statements
|
333
|
-
statements = []
|
334
|
-
if @obj.error_messages.size > 0
|
335
|
-
raise DomainObjectInitError, @obj.error_messages, caller
|
336
|
-
end
|
337
|
-
@obj.class.self_and_concrete_superclasses.each { |domain_class|
|
338
|
-
statements << statement_bind_value_pair( domain_class )
|
339
|
-
}
|
340
|
-
statements.reverse
|
341
|
-
end
|
342
|
-
|
343
|
-
def statement_bind_value_pair( domain_class )
|
344
|
-
@bind_values = []
|
345
|
-
if @obj.pk_id == nil
|
346
|
-
statement = insert_sql( domain_class )
|
347
|
-
else
|
348
|
-
if @obj.delete
|
349
|
-
statement = delete_sql( domain_class )
|
350
|
-
else
|
351
|
-
statement = update_sql( domain_class)
|
352
|
-
end
|
353
|
-
end
|
354
|
-
[statement, @bind_values]
|
355
|
-
end
|
356
|
-
|
357
|
-
def update_sql( domain_class )
|
358
|
-
nameValueStrings = []
|
359
|
-
nameValuePairs = get_name_value_pairs( domain_class )
|
360
|
-
nameValuePairs.each { |key, value|
|
361
|
-
nameValueStrings << "#{key}=#{ value }"
|
362
|
-
}
|
363
|
-
allNameValues = nameValueStrings.join ', '
|
364
|
-
"update #{ domain_class.table_name} set #{allNameValues} " +
|
365
|
-
"where #{ domain_class.sql_primary_key_name}=#{@obj.pk_id}"
|
66
|
+
db_object.to_s
|
366
67
|
end
|
367
68
|
end
|
368
69
|
|
@@ -432,81 +133,63 @@ module Lafcadio
|
|
432
133
|
# Since these triggers are executed in Ruby, they're easy to test. See
|
433
134
|
# DomainObject#pre_commit_trigger and DomainObject#post_commit_trigger for more.
|
434
135
|
class ObjectStore < ContextualService::Service
|
435
|
-
def self.
|
436
|
-
DbConnection.set_db_name dbName
|
437
|
-
end
|
136
|
+
def self.mock?; get_object_store.mock?; end
|
438
137
|
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
# myDomainObject.commit
|
446
|
-
def commit(db_object)
|
447
|
-
@cache.commit( db_object )
|
448
|
-
db_object
|
138
|
+
@@db_bridge = nil
|
139
|
+
|
140
|
+
def self.db_bridge; @@db_bridge ||= DbBridge.new; end
|
141
|
+
|
142
|
+
def self.db_name= (dbName) #:nodoc:
|
143
|
+
DbConnection.db_name= dbName
|
449
144
|
end
|
450
145
|
|
451
|
-
|
452
|
-
|
453
|
-
@cache.flush db_object
|
146
|
+
def initialize #:nodoc:
|
147
|
+
@cache = ObjectStore::Cache.new self.class.db_bridge
|
454
148
|
end
|
455
149
|
|
456
150
|
# Returns the domain object corresponding to the domain class and pk_id.
|
457
151
|
def get( domain_class, pk_id )
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
152
|
+
@cache.get_by_query( Query.new( domain_class, pk_id ) ).first or (
|
153
|
+
raise(
|
154
|
+
DomainObjectNotFoundError, "Can't find #{domain_class} #{pk_id}",
|
155
|
+
caller
|
156
|
+
)
|
157
|
+
)
|
462
158
|
end
|
463
159
|
|
464
160
|
# Returns all domain objects for the given domain class.
|
465
|
-
def get_all(domain_class)
|
161
|
+
def get_all(domain_class)
|
162
|
+
@cache.get_by_query( Query.new( domain_class ) )
|
163
|
+
end
|
466
164
|
|
467
165
|
# Returns the DbBridge; this is useful in case you need to use raw SQL for a
|
468
166
|
# specific query.
|
469
|
-
def get_db_bridge; @
|
167
|
+
def get_db_bridge; @cache.db_bridge; end
|
470
168
|
|
471
|
-
def get_field_name( domain_object )
|
472
|
-
domain_object.domain_class.basename.camel_case_to_underscore
|
473
|
-
end
|
474
|
-
|
475
169
|
def get_filtered(domain_class_name, searchTerm, fieldName = nil) #:nodoc:
|
476
|
-
domain_class =
|
477
|
-
domain_class_name
|
478
|
-
)
|
170
|
+
domain_class = Class.by_name domain_class_name
|
479
171
|
unless fieldName
|
480
|
-
fieldName = domain_class.
|
172
|
+
fieldName = domain_class.link_field( searchTerm.domain_class ).name
|
481
173
|
end
|
482
174
|
get_subset( Query::Equals.new( fieldName, searchTerm, domain_class ) )
|
483
175
|
end
|
484
176
|
|
485
|
-
def get_map_match( domain_class, mapped ) #:nodoc:
|
486
|
-
Query::Equals.new( get_field_name( mapped ), mapped, domain_class )
|
487
|
-
end
|
488
|
-
|
489
177
|
def get_map_object( domain_class, map1, map2 ) #:nodoc:
|
490
178
|
unless map1 && map2
|
491
179
|
raise ArgumentError,
|
492
180
|
"ObjectStore#get_map_object needs two non-nil keys", caller
|
493
181
|
end
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
resultType = DomainObject.get_domain_class_from_string resultTypeName
|
502
|
-
firstTypeName = searchTerm.class.basename
|
503
|
-
secondTypeName = resultType.basename
|
504
|
-
mapTypeName = firstTypeName + secondTypeName
|
505
|
-
get_filtered( mapTypeName, searchTerm ).collect { |mapObj|
|
506
|
-
mapObj.send( resultType.name.decapitalize )
|
182
|
+
query = Query.infer( domain_class ) { |dobj|
|
183
|
+
dobj.send(
|
184
|
+
map1.domain_class.basename.camel_case_to_underscore
|
185
|
+
).equals( map1 ) &
|
186
|
+
dobj.send(
|
187
|
+
map2.domain_class.basename.camel_case_to_underscore
|
188
|
+
).equals( map2 )
|
507
189
|
}
|
190
|
+
get_subset( query ).first
|
508
191
|
end
|
509
|
-
|
192
|
+
|
510
193
|
# Retrieves the maximum value across all instances of one domain class.
|
511
194
|
# ObjectStore#get_max( Client )
|
512
195
|
# returns the highest +pk_id+ in the +clients+ table.
|
@@ -514,7 +197,7 @@ module Lafcadio
|
|
514
197
|
# will return the highest rate for all invoices.
|
515
198
|
def get_max( domain_class, field_name = 'pk_id' )
|
516
199
|
qry = Query::Max.new( domain_class, field_name )
|
517
|
-
@
|
200
|
+
@cache.group_query( qry ).only[:max]
|
518
201
|
end
|
519
202
|
|
520
203
|
# Retrieves a collection of domain objects by +pk_id+.
|
@@ -542,169 +225,476 @@ module Lafcadio
|
|
542
225
|
@cache.get_by_query( query )
|
543
226
|
end
|
544
227
|
|
545
|
-
def last_commit_time( domain_class, pk_id ) #:nodoc:
|
546
|
-
@cache.last_commit_time( domain_class, pk_id )
|
547
|
-
end
|
548
|
-
|
549
228
|
def method_missing(methodId, *args) #:nodoc:
|
550
|
-
|
551
|
-
|
552
|
-
|
229
|
+
if [ :commit, :flush, :last_commit_time ].include?( methodId )
|
230
|
+
@cache.send( methodId, *args )
|
231
|
+
else
|
232
|
+
proc = block_given? ? ( proc { |obj| yield( obj ) } ) : nil
|
233
|
+
dispatch = MethodDispatch.new( methodId, proc, *args )
|
234
|
+
if dispatch.symbol
|
235
|
+
self.send( dispatch.symbol, *dispatch.args )
|
236
|
+
else
|
237
|
+
super
|
238
|
+
end
|
239
|
+
end
|
553
240
|
end
|
554
241
|
|
555
242
|
def mock? #:nodoc:
|
556
243
|
false
|
557
244
|
end
|
558
245
|
|
559
|
-
def query( query ); @
|
246
|
+
def query( query ); @cache.group_query( query ); end
|
560
247
|
|
561
248
|
def respond_to?( symbol, include_private = false )
|
562
|
-
|
563
|
-
|
564
|
-
|
249
|
+
if MethodDispatch.new( symbol ).symbol
|
250
|
+
true
|
251
|
+
else
|
565
252
|
super
|
566
253
|
end
|
567
254
|
end
|
568
255
|
|
569
|
-
def transaction( &action ); @
|
256
|
+
def transaction( &action ); @cache.transaction( action ); end
|
570
257
|
|
571
258
|
class Cache #:nodoc:
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
@
|
576
|
-
@
|
259
|
+
attr_reader :db_bridge
|
260
|
+
|
261
|
+
def initialize( db_bridge = DbBridge.new )
|
262
|
+
@db_bridge = db_bridge
|
263
|
+
@domain_class_caches = {}
|
577
264
|
end
|
578
265
|
|
579
266
|
def commit( db_object )
|
580
|
-
|
581
|
-
|
267
|
+
db_object.verify if LafcadioConfig.new()['checkFields'] == 'onCommit'
|
268
|
+
db_object.last_commit_type = get_last_commit db_object
|
269
|
+
db_object.pre_commit_trigger
|
270
|
+
update_dependent_domain_objects( db_object ) if db_object.delete
|
271
|
+
@db_bridge.commit db_object
|
272
|
+
db_object.pk_id = @db_bridge.last_pk_id_inserted unless db_object.pk_id
|
273
|
+
update_after_commit db_object
|
274
|
+
db_object.post_commit_trigger
|
275
|
+
db_object
|
582
276
|
end
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
277
|
+
|
278
|
+
def cache( domain_class )
|
279
|
+
unless @domain_class_caches[domain_class]
|
280
|
+
@domain_class_caches[domain_class] = DomainClassCache.new(
|
281
|
+
domain_class, @db_bridge
|
282
|
+
)
|
283
|
+
end
|
284
|
+
@domain_class_caches[domain_class]
|
588
285
|
end
|
589
286
|
|
590
|
-
def
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
287
|
+
def get_last_commit( db_object )
|
288
|
+
if db_object.delete
|
289
|
+
DomainObject::COMMIT_DELETE
|
290
|
+
elsif db_object.pk_id
|
291
|
+
DomainObject::COMMIT_EDIT
|
292
|
+
else
|
293
|
+
DomainObject::COMMIT_ADD
|
294
|
+
end
|
596
295
|
end
|
597
296
|
|
598
|
-
|
599
|
-
|
600
|
-
|
297
|
+
def method_missing( meth, *args )
|
298
|
+
simple_dispatch = [
|
299
|
+
:get_by_query, :queries, :save, :set_commit_time,
|
300
|
+
:update_after_commit
|
301
|
+
]
|
302
|
+
if simple_dispatch.include?( meth )
|
303
|
+
cache( args.first.domain_class ).send( meth, *args )
|
304
|
+
elsif [ :[], :last_commit_time ].include?( meth )
|
305
|
+
cache( args.first ).send( meth, *args[1..-1] )
|
306
|
+
elsif [ :group_query, :transaction ].include?( meth )
|
307
|
+
@db_bridge.send( meth, *args )
|
308
|
+
end
|
601
309
|
end
|
602
310
|
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
311
|
+
def update_dependent_domain_class( db_object, aClass, field )
|
312
|
+
object_store = ObjectStore.get_object_store
|
313
|
+
collection = object_store.get_filtered(
|
314
|
+
aClass.name, db_object, field.name
|
315
|
+
)
|
316
|
+
collection.each { |dependentObject|
|
317
|
+
if field.delete_cascade
|
318
|
+
dependentObject.delete = true
|
319
|
+
else
|
320
|
+
dependentObject.send( field.name + '=', nil )
|
321
|
+
end
|
322
|
+
object_store.commit dependentObject
|
607
323
|
}
|
608
324
|
end
|
609
325
|
|
610
|
-
def
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
326
|
+
def update_dependent_domain_objects( db_object )
|
327
|
+
dependent_classes = db_object.domain_class.dependent_classes
|
328
|
+
dependent_classes.keys.each { |aClass|
|
329
|
+
update_dependent_domain_class(
|
330
|
+
db_object, aClass, dependent_classes[aClass]
|
331
|
+
)
|
332
|
+
}
|
333
|
+
end
|
334
|
+
|
335
|
+
class DomainClassCache < Hash
|
336
|
+
attr_reader :commit_times, :domain_class, :queries
|
337
|
+
|
338
|
+
def initialize( domain_class, db_bridge )
|
339
|
+
super()
|
340
|
+
@domain_class, @db_bridge = domain_class, db_bridge
|
341
|
+
@commit_times = {}
|
342
|
+
@queries = {}
|
343
|
+
end
|
344
|
+
|
345
|
+
def []( pk_id )
|
346
|
+
dobj = super
|
347
|
+
dobj ? dobj.clone : nil
|
348
|
+
end
|
349
|
+
|
350
|
+
def collect_from_superset( query )
|
351
|
+
if ( pk_ids = find_superset_pk_ids( query ) )
|
352
|
+
queries[query] = ( pk_ids.collect { |pk_id|
|
353
|
+
self[ pk_id ]
|
619
354
|
} ).select { |dobj| query.object_meets( dobj ) }.collect { |dobj|
|
620
355
|
dobj.pk_id
|
621
356
|
}
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
357
|
+
true
|
358
|
+
else
|
359
|
+
false
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def find_superset_pk_ids( query )
|
364
|
+
superset_query, pk_ids =
|
365
|
+
queries.find { |other_query, pk_ids|
|
366
|
+
query.implies?( other_query )
|
627
367
|
}
|
368
|
+
pk_ids
|
369
|
+
end
|
370
|
+
|
371
|
+
# Flushes a domain object.
|
372
|
+
def flush( db_object )
|
373
|
+
delete db_object.pk_id
|
374
|
+
flush_queries
|
375
|
+
end
|
376
|
+
|
377
|
+
def flush_queries
|
378
|
+
queries.keys.each do |query|
|
379
|
+
queries.delete( query ) if query.domain_class == domain_class
|
628
380
|
end
|
629
381
|
end
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
382
|
+
|
383
|
+
def get_by_query( query )
|
384
|
+
unless queries[query]
|
385
|
+
collected = collect_from_superset query
|
386
|
+
if !collected and queries.values
|
387
|
+
query_db query
|
388
|
+
end
|
389
|
+
end
|
390
|
+
collection = []
|
391
|
+
queries[query].each { |pk_id|
|
392
|
+
dobj = self[ pk_id ]
|
393
|
+
collection << dobj if dobj
|
394
|
+
}
|
395
|
+
collection
|
396
|
+
end
|
397
|
+
|
398
|
+
def last_commit_time( pk_id ); commit_times[pk_id]; end
|
399
|
+
|
400
|
+
def query_db( query )
|
401
|
+
newObjects = @db_bridge.select_dobjs query
|
402
|
+
newObjects.each { |dbObj| save dbObj }
|
403
|
+
queries[query] = newObjects.collect { |dobj| dobj.pk_id }
|
404
|
+
end
|
405
|
+
|
406
|
+
# Saves a domain object.
|
407
|
+
def save(db_object)
|
408
|
+
self[db_object.pk_id] = db_object
|
409
|
+
flush_queries
|
410
|
+
end
|
411
|
+
|
412
|
+
def set_commit_time( d_obj ); commit_times[d_obj.pk_id] = Time.now; end
|
413
|
+
|
414
|
+
def update_after_commit( db_object ) #:nodoc:
|
415
|
+
if [ DomainObject::COMMIT_EDIT, DomainObject::COMMIT_ADD ].include?(
|
416
|
+
db_object.last_commit_type
|
417
|
+
)
|
418
|
+
save db_object
|
419
|
+
elsif db_object.last_commit_type == DomainObject::COMMIT_DELETE
|
420
|
+
flush db_object
|
421
|
+
end
|
422
|
+
set_commit_time db_object
|
423
|
+
end
|
636
424
|
end
|
425
|
+
end
|
637
426
|
|
638
|
-
|
639
|
-
|
640
|
-
|
427
|
+
class CommitSqlStatementsAndBinds < Array #:nodoc:
|
428
|
+
attr_reader :bind_values
|
429
|
+
|
430
|
+
def initialize( obj )
|
431
|
+
@obj = obj
|
432
|
+
reversed = []
|
433
|
+
@obj.class.self_and_concrete_superclasses.each { |domain_class|
|
434
|
+
reversed << statement_bind_value_pair( domain_class )
|
435
|
+
}
|
436
|
+
reversed.reverse.each do |statement, binds|
|
437
|
+
self << [ statement, binds ]
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def delete_sql( domain_class )
|
442
|
+
"delete from #{ domain_class.table_name} " +
|
443
|
+
"where #{ domain_class.sql_primary_key_name }=#{ @obj.pk_id }"
|
444
|
+
end
|
445
|
+
|
446
|
+
def get_name_value_pairs( domain_class )
|
447
|
+
nameValues = []
|
448
|
+
domain_class.class_fields.each { |field|
|
449
|
+
unless field.instance_of?( PrimaryKeyField )
|
450
|
+
value = @obj.send(field.name)
|
451
|
+
unless field.db_will_automatically_write?
|
452
|
+
nameValues << field.db_field_name
|
453
|
+
nameValues << field.value_for_sql( value )
|
454
|
+
end
|
455
|
+
if field.bind_write?
|
456
|
+
@bind_values << value
|
457
|
+
end
|
458
|
+
end
|
459
|
+
}
|
460
|
+
QueueHash.new( *nameValues )
|
461
|
+
end
|
462
|
+
|
463
|
+
def insert_sql( domain_class )
|
464
|
+
fields = domain_class.class_fields
|
465
|
+
nameValuePairs = get_name_value_pairs( domain_class )
|
466
|
+
if domain_class.is_child_domain_class?
|
467
|
+
nameValuePairs[domain_class.sql_primary_key_name] = 'LAST_INSERT_ID()'
|
468
|
+
end
|
469
|
+
fieldNameStr = nameValuePairs.keys.join ", "
|
470
|
+
fieldValueStr = nameValuePairs.values.join ", "
|
471
|
+
"insert into #{ domain_class.table_name}(#{fieldNameStr}) " +
|
472
|
+
"values(#{fieldValueStr})"
|
473
|
+
end
|
474
|
+
|
475
|
+
def statement_bind_value_pair( domain_class )
|
476
|
+
@bind_values = []
|
477
|
+
if @obj.pk_id == nil
|
478
|
+
statement = insert_sql( domain_class )
|
479
|
+
else
|
480
|
+
if @obj.delete
|
481
|
+
statement = delete_sql( domain_class )
|
482
|
+
else
|
483
|
+
statement = update_sql( domain_class)
|
484
|
+
end
|
641
485
|
end
|
642
|
-
@
|
486
|
+
[statement, @bind_values]
|
643
487
|
end
|
488
|
+
|
489
|
+
def update_sql( domain_class )
|
490
|
+
nameValueStrings = []
|
491
|
+
nameValuePairs = get_name_value_pairs( domain_class )
|
492
|
+
nameValuePairs.each { |key, value|
|
493
|
+
nameValueStrings << "#{key}=#{ value }"
|
494
|
+
}
|
495
|
+
allNameValues = nameValueStrings.join ', '
|
496
|
+
"update #{ domain_class.table_name} set #{allNameValues} " +
|
497
|
+
"where #{ domain_class.sql_primary_key_name}=#{@obj.pk_id}"
|
498
|
+
end
|
499
|
+
end
|
644
500
|
|
645
|
-
|
646
|
-
|
647
|
-
|
501
|
+
class DbBridge #:nodoc:
|
502
|
+
@@last_pk_id_inserted = nil
|
503
|
+
|
504
|
+
def self._load(aString)
|
505
|
+
aString =~ /db_conn:/
|
506
|
+
db_conn_str = $'
|
507
|
+
begin
|
508
|
+
db_conn = Marshal.load db_conn_str
|
509
|
+
rescue TypeError
|
510
|
+
db_conn = nil
|
511
|
+
end
|
512
|
+
DbConnection.set_db_connection db_conn
|
513
|
+
new
|
648
514
|
end
|
649
515
|
|
650
|
-
def
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
516
|
+
def initialize
|
517
|
+
@db_conn = DbConnection.get_db_connection
|
518
|
+
ObjectSpace.define_finalizer( self, proc { |id|
|
519
|
+
DbConnection.get_db_connection.disconnect
|
520
|
+
} )
|
521
|
+
end
|
522
|
+
|
523
|
+
def _dump(aDepth)
|
524
|
+
dbDump = @dbh.respond_to?( '_dump' ) ? @dbh._dump : @dbh.class.to_s
|
525
|
+
"dbh:#{dbDump}"
|
526
|
+
end
|
527
|
+
|
528
|
+
def commit(db_object)
|
529
|
+
statements_and_binds = ObjectStore::CommitSqlStatementsAndBinds.new(
|
530
|
+
db_object
|
531
|
+
)
|
532
|
+
statements_and_binds.each do |sql, binds|
|
533
|
+
@db_conn.do( sql, *binds )
|
534
|
+
end
|
535
|
+
if statements_and_binds[0].first =~ /insert/
|
536
|
+
sql = 'select last_insert_id()'
|
537
|
+
result = select_all( sql )
|
538
|
+
@@last_pk_id_inserted = result[0]['last_insert_id()'].to_i
|
655
539
|
end
|
656
|
-
by_domain_class[d_obj.pk_id] = Time.now
|
657
540
|
end
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
541
|
+
|
542
|
+
def group_query( query )
|
543
|
+
select_all( query.to_sql ).map { |row| query.result_row( row ) }
|
544
|
+
end
|
545
|
+
|
546
|
+
def last_pk_id_inserted; @@last_pk_id_inserted; end
|
547
|
+
|
548
|
+
def maybe_log(sql)
|
549
|
+
config = LafcadioConfig.new
|
550
|
+
if config['logSql'] == 'y'
|
551
|
+
sqllog = Log4r::Logger['sql'] || Log4r::Logger.new( 'sql' )
|
552
|
+
filename = File.join(
|
553
|
+
config['logdir'], config['sqlLogFile'] || 'sql'
|
554
|
+
)
|
555
|
+
outputter = Log4r::FileOutputter.new(
|
556
|
+
'outputter', { :filename => filename }
|
557
|
+
)
|
558
|
+
sqllog.outputters = outputter
|
559
|
+
sqllog.info sql
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def select_all(sql)
|
564
|
+
maybe_log sql
|
565
|
+
begin
|
566
|
+
@db_conn.select_all( sql )
|
567
|
+
rescue DBI::DatabaseError => e
|
568
|
+
raise $!.to_s + ": #{ e.errstr }"
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
def select_dobjs(query)
|
573
|
+
domain_class = query.domain_class
|
574
|
+
select_all( query.to_sql ).collect { |row_hash|
|
575
|
+
domain_class.new( SqlToRubyValues.new( domain_class, row_hash ) )
|
576
|
+
}
|
577
|
+
end
|
578
|
+
|
579
|
+
def transaction( action )
|
580
|
+
tr = Transaction.new @db_conn
|
581
|
+
tr.commit
|
582
|
+
begin
|
583
|
+
action.call tr
|
584
|
+
tr.commit
|
585
|
+
rescue RollbackError
|
586
|
+
# rollback handled by Transaction
|
587
|
+
rescue
|
588
|
+
err_to_raise = $!
|
589
|
+
tr.rollback false
|
590
|
+
raise err_to_raise
|
591
|
+
end
|
664
592
|
end
|
665
593
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
594
|
+
class Transaction
|
595
|
+
def initialize( db_conn ); @db_conn = db_conn; end
|
596
|
+
|
597
|
+
def commit; @db_conn.commit; end
|
598
|
+
|
599
|
+
def rollback( raise_error = true )
|
600
|
+
@db_conn.rollback
|
601
|
+
raise RollbackError if raise_error
|
672
602
|
end
|
673
|
-
set_commit_time( committer.db_object )
|
674
603
|
end
|
604
|
+
|
605
|
+
class RollbackError < StandardError; end
|
675
606
|
end
|
676
607
|
|
608
|
+
class DbConnection < ContextualService::Service
|
609
|
+
@@conn_class = DBI
|
610
|
+
@@db_name = nil
|
611
|
+
|
612
|
+
def self.connection_class=( aClass ); @@conn_class = aClass; end
|
613
|
+
|
614
|
+
def self.db_name=( db_name ); @@db_name = db_name; end
|
615
|
+
|
616
|
+
def initialize; @dbh = load_new_dbh; end
|
617
|
+
|
618
|
+
def disconnect; @dbh.disconnect; end
|
619
|
+
|
620
|
+
def load_new_dbh
|
621
|
+
config = LafcadioConfig.new
|
622
|
+
dbName = @@db_name || config['dbname']
|
623
|
+
dbAndHost = nil
|
624
|
+
if dbName && config['dbhost']
|
625
|
+
dbAndHost = "dbi:Mysql:#{ dbName }:#{ config['dbhost'] }"
|
626
|
+
else
|
627
|
+
dbAndHost = "dbi:#{config['dbconn']}"
|
628
|
+
end
|
629
|
+
dbh = @@conn_class.connect(
|
630
|
+
dbAndHost, config['dbuser'], config['dbpassword']
|
631
|
+
)
|
632
|
+
dbh['AutoCommit'] = false
|
633
|
+
dbh
|
634
|
+
end
|
635
|
+
|
636
|
+
def method_missing( symbol, *args )
|
637
|
+
@dbh.send( symbol, *args )
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
677
641
|
class MethodDispatch #:nodoc:
|
678
642
|
attr_reader :symbol, :args
|
679
643
|
|
680
644
|
def initialize( orig_method, *other_args )
|
681
645
|
@orig_method = orig_method
|
682
646
|
@orig_args = other_args
|
683
|
-
if @orig_args.size > 0
|
684
|
-
@maybe_proc = @orig_args.shift
|
685
|
-
end
|
647
|
+
@maybe_proc = @orig_args.shift if @orig_args.size > 0
|
686
648
|
@methodName = orig_method.id2name
|
687
|
-
if @methodName =~ /^get(.*)$/
|
688
|
-
|
689
|
-
|
690
|
-
|
649
|
+
dispatch_get_method if @methodName =~ /^get(.*)$/
|
650
|
+
end
|
651
|
+
|
652
|
+
def camel_case_method_name_after_get
|
653
|
+
@orig_method.id2name =~ /^get(.*)$/
|
654
|
+
$1.underscore_to_camel_case
|
655
|
+
end
|
656
|
+
|
657
|
+
def dispatch_get_all
|
658
|
+
@symbol = :get_all
|
659
|
+
@args = [ @domain_class ]
|
660
|
+
end
|
661
|
+
|
662
|
+
def dispatch_get_filtered( searchTerm, fieldName )
|
663
|
+
@symbol = :get_filtered
|
664
|
+
@args = [ @domain_class.name, searchTerm, fieldName ]
|
665
|
+
end
|
666
|
+
|
667
|
+
def dispatch_get_map_object( domain_class )
|
668
|
+
@symbol = :get_map_object
|
669
|
+
@args = [ domain_class, @orig_args[0], @orig_args[1] ]
|
670
|
+
end
|
671
|
+
|
672
|
+
def dispatch_get_method
|
673
|
+
unless ( dispatch_get_singular )
|
674
|
+
domain_class_name = camel_case_method_name_after_get.singular
|
675
|
+
begin
|
676
|
+
@domain_class = Module.by_name domain_class_name
|
677
|
+
dispatch_get_plural
|
678
|
+
rescue NameError
|
679
|
+
# skip it
|
680
|
+
end
|
691
681
|
end
|
692
682
|
end
|
693
683
|
|
694
684
|
def dispatch_get_plural
|
695
685
|
if @orig_args.size == 0 && @maybe_proc.nil?
|
696
|
-
|
697
|
-
@args = [ @domain_class ]
|
686
|
+
dispatch_get_all
|
698
687
|
else
|
699
|
-
searchTerm = @orig_args[0]
|
700
|
-
fieldName = @orig_args[1]
|
688
|
+
searchTerm, fieldName = @orig_args[0..1]
|
701
689
|
if searchTerm.nil? && @maybe_proc.nil? && fieldName.nil?
|
702
|
-
|
703
|
-
|
704
|
-
|
690
|
+
raise_get_plural_needs_field_arg_if_first_arg_nil
|
691
|
+
elsif !@maybe_proc.nil? && searchTerm.nil?
|
692
|
+
dispatch_get_plural_by_query_block
|
693
|
+
elsif @maybe_proc.nil? && ( !( searchTerm.nil? && fieldName.nil? ) )
|
694
|
+
dispatch_get_filtered( searchTerm, fieldName )
|
695
|
+
else
|
696
|
+
raise_get_plural_cant_have_both_query_block_and_search_term
|
705
697
|
end
|
706
|
-
dispatch_get_plural_by_query_block_or_search_term( searchTerm,
|
707
|
-
fieldName )
|
708
698
|
end
|
709
699
|
end
|
710
700
|
|
@@ -716,94 +706,63 @@ module Lafcadio
|
|
716
706
|
@args = [ inferrer.execute ]
|
717
707
|
end
|
718
708
|
|
719
|
-
def
|
720
|
-
fieldName )
|
721
|
-
if !@maybe_proc.nil? && searchTerm.nil?
|
722
|
-
dispatch_get_plural_by_query_block
|
723
|
-
elsif @maybe_proc.nil? && ( !( searchTerm.nil? && fieldName.nil? ) )
|
724
|
-
@symbol = :get_filtered
|
725
|
-
@args = [ @domain_class.name, searchTerm, fieldName ]
|
726
|
-
else
|
727
|
-
raise( ArgumentError,
|
728
|
-
"Shouldn't send both a query block and a search term",
|
729
|
-
caller )
|
730
|
-
end
|
731
|
-
end
|
732
|
-
|
733
|
-
def dispatch_get_method
|
709
|
+
def dispatch_get_singular
|
734
710
|
begin
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
raise_no_method_error
|
711
|
+
domain_class = Module.by_name camel_case_method_name_after_get
|
712
|
+
if @orig_args[0].class <= Integer
|
713
|
+
@symbol = :get
|
714
|
+
@args = [ domain_class, @orig_args[0] ]
|
715
|
+
elsif @orig_args[0].class <= DomainObject
|
716
|
+
dispatch_get_map_object domain_class
|
717
|
+
elsif @orig_args.empty?
|
718
|
+
@symbol = :get
|
744
719
|
end
|
720
|
+
true
|
721
|
+
rescue NameError
|
722
|
+
false
|
745
723
|
end
|
746
724
|
end
|
747
725
|
|
748
|
-
def
|
749
|
-
|
750
|
-
|
751
|
-
)
|
752
|
-
if @orig_args[0].class <= Integer
|
753
|
-
@symbol = :get
|
754
|
-
@args = [ domain_class, @orig_args[0] ]
|
755
|
-
elsif @orig_args[0].class <= DomainObject
|
756
|
-
@symbol = :get_map_object
|
757
|
-
@args = [ domain_class, @orig_args[0], @orig_args[1] ]
|
758
|
-
end
|
759
|
-
end
|
760
|
-
|
761
|
-
def camel_case_method_name_after_get
|
762
|
-
@orig_method.id2name =~ /^get(.*)$/
|
763
|
-
$1.underscore_to_camel_case
|
726
|
+
def raise_get_plural_needs_field_arg_if_first_arg_nil
|
727
|
+
msg = "ObjectStore\##{ @orig_method } needs a field name as its " +
|
728
|
+
"second argument if its first argument is nil"
|
729
|
+
raise( ArgumentError, msg, caller )
|
764
730
|
end
|
765
731
|
|
766
|
-
def
|
767
|
-
raise(
|
732
|
+
def raise_get_plural_cant_have_both_query_block_and_search_term
|
733
|
+
raise(
|
734
|
+
ArgumentError, "Shouldn't send both a query block and a search term",
|
735
|
+
caller
|
736
|
+
)
|
768
737
|
end
|
769
738
|
end
|
770
|
-
end
|
771
|
-
|
772
|
-
class SqlValueConverter < Hash #:nodoc:
|
773
|
-
attr_reader :domain_class, :row_hash
|
774
739
|
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
field = @domain_class.
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
740
|
+
class SqlToRubyValues #:nodoc:
|
741
|
+
attr_reader :domain_class, :row_hash
|
742
|
+
|
743
|
+
def initialize( domain_class, row_hash )
|
744
|
+
@domain_class = domain_class
|
745
|
+
@row_hash = row_hash
|
746
|
+
end
|
747
|
+
|
748
|
+
def []( key )
|
749
|
+
if ( field = @domain_class.field key )
|
750
|
+
val = field.value_from_sql( @row_hash[ field.db_field_name ] )
|
751
|
+
if field.instance_of?( PrimaryKeyField ) && val.nil?
|
752
|
+
raise FieldMatchError, error_msg, caller
|
753
|
+
else
|
754
|
+
val
|
755
|
+
end
|
791
756
|
else
|
792
|
-
|
757
|
+
nil
|
793
758
|
end
|
794
|
-
rescue MissingError
|
795
|
-
nil
|
796
759
|
end
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
def error_msg
|
804
|
-
"The field \"" + @domain_class.sql_primary_key_name +
|
805
|
-
"\" can\'t be found in the table \"" +
|
806
|
-
@domain_class.table_name + "\"."
|
760
|
+
|
761
|
+
def error_msg
|
762
|
+
"The field \"" + @domain_class.sql_primary_key_name +
|
763
|
+
"\" can\'t be found in the table \"" +
|
764
|
+
@domain_class.table_name + "\"."
|
765
|
+
end
|
807
766
|
end
|
808
767
|
end
|
809
768
|
end
|