lafcadio 0.4.3 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/lafcadio_schema +28 -0
- data/lib/lafcadio.rb +3 -4
- data/lib/lafcadio.rb~ +3 -4
- data/lib/lafcadio/TestSuite.rb +2 -0
- data/lib/lafcadio/TestSuite.rb~ +16 -0
- data/lib/lafcadio/dateTime.rb +93 -2
- data/lib/lafcadio/{dateTime/Month.rb → dateTime.rb~} +33 -33
- data/lib/lafcadio/depend.rb +3 -0
- data/lib/lafcadio/domain.rb +574 -70
- data/lib/lafcadio/domain.rb~ +570 -70
- data/lib/lafcadio/mock.rb +92 -2
- data/lib/lafcadio/mock.rb~ +93 -0
- data/lib/lafcadio/objectField.rb +614 -3
- data/lib/lafcadio/objectField.rb~ +618 -0
- data/lib/lafcadio/objectStore.rb +662 -19
- data/lib/lafcadio/objectStore.rb~ +746 -0
- data/lib/lafcadio/query.rb +415 -31
- data/lib/lafcadio/query.rb~ +572 -0
- data/lib/lafcadio/schema.rb +57 -2
- data/lib/lafcadio/test.rb +17 -2
- data/lib/lafcadio/{test/LafcadioTestCase.rb → test.rb~} +5 -5
- data/lib/lafcadio/test/testconfig.dat +1 -1
- data/lib/lafcadio/util.rb +337 -20
- metadata +16 -77
- data/lib/lafcadio/domain/DomainObject.rb +0 -375
- data/lib/lafcadio/domain/DomainObject.rb~ +0 -371
- data/lib/lafcadio/domain/MapObject.rb +0 -22
- data/lib/lafcadio/domain/ObjectType.rb +0 -80
- data/lib/lafcadio/includer.rb +0 -18
- data/lib/lafcadio/mock/MockDbBridge.rb +0 -78
- data/lib/lafcadio/mock/MockDbBridge.rb~ +0 -74
- data/lib/lafcadio/mock/MockObjectStore.rb +0 -20
- data/lib/lafcadio/objectField/AutoIncrementField.rb +0 -25
- data/lib/lafcadio/objectField/BooleanField.rb +0 -83
- data/lib/lafcadio/objectField/DateField.rb +0 -33
- data/lib/lafcadio/objectField/DateTimeField.rb +0 -25
- data/lib/lafcadio/objectField/DecimalField.rb +0 -41
- data/lib/lafcadio/objectField/EmailField.rb +0 -28
- data/lib/lafcadio/objectField/EnumField.rb +0 -62
- data/lib/lafcadio/objectField/FieldValueError.rb +0 -4
- data/lib/lafcadio/objectField/IntegerField.rb +0 -15
- data/lib/lafcadio/objectField/LinkField.rb +0 -92
- data/lib/lafcadio/objectField/LinkField.rb~ +0 -86
- data/lib/lafcadio/objectField/MoneyField.rb +0 -13
- data/lib/lafcadio/objectField/MonthField.rb +0 -16
- data/lib/lafcadio/objectField/ObjectField.rb +0 -142
- data/lib/lafcadio/objectField/PasswordField.rb +0 -29
- data/lib/lafcadio/objectField/StateField.rb +0 -13
- data/lib/lafcadio/objectField/SubsetLinkField.rb +0 -25
- data/lib/lafcadio/objectField/TextField.rb +0 -23
- data/lib/lafcadio/objectField/TextListField.rb +0 -21
- data/lib/lafcadio/objectField/TimeStampField.rb +0 -15
- data/lib/lafcadio/objectStore/Cache.rb +0 -81
- data/lib/lafcadio/objectStore/Committer.rb +0 -65
- data/lib/lafcadio/objectStore/CouldntMatchObjectTypeError.rb +0 -4
- data/lib/lafcadio/objectStore/DbBridge.rb +0 -140
- data/lib/lafcadio/objectStore/DbBridge.rb~ +0 -140
- data/lib/lafcadio/objectStore/DomainComparable.rb +0 -25
- data/lib/lafcadio/objectStore/DomainObjectInitError.rb +0 -9
- data/lib/lafcadio/objectStore/DomainObjectNotFoundError.rb +0 -4
- data/lib/lafcadio/objectStore/DomainObjectProxy.rb +0 -62
- data/lib/lafcadio/objectStore/DomainObjectSqlMaker.rb +0 -74
- data/lib/lafcadio/objectStore/ObjectStore.rb +0 -207
- data/lib/lafcadio/objectStore/ObjectStore.rb~ +0 -207
- data/lib/lafcadio/objectStore/SqlValueConverter.rb +0 -30
- data/lib/lafcadio/objectStore/SqlValueConverter.rb~ +0 -30
- data/lib/lafcadio/query/Compare.rb +0 -55
- data/lib/lafcadio/query/CompoundCondition.rb +0 -39
- data/lib/lafcadio/query/Condition.rb +0 -66
- data/lib/lafcadio/query/Condition.rb~ +0 -66
- data/lib/lafcadio/query/Equals.rb +0 -45
- data/lib/lafcadio/query/In.rb +0 -20
- data/lib/lafcadio/query/Like.rb +0 -48
- data/lib/lafcadio/query/Link.rb +0 -20
- data/lib/lafcadio/query/Max.rb +0 -32
- data/lib/lafcadio/query/Max.rb~ +0 -25
- data/lib/lafcadio/query/Not.rb +0 -21
- data/lib/lafcadio/query/Query.rb +0 -92
- data/lib/lafcadio/schema/CreateTableStatement.rb +0 -61
- data/lib/lafcadio/schema/CreateTableStatement.rb~ +0 -59
- data/lib/lafcadio/util/Context.rb +0 -61
- data/lib/lafcadio/util/ContextualService.rb +0 -33
- data/lib/lafcadio/util/English.rb +0 -117
- data/lib/lafcadio/util/HashOfArrays.rb +0 -48
- data/lib/lafcadio/util/LafcadioConfig.rb +0 -25
- data/lib/lafcadio/util/QueueHash.rb +0 -67
- data/lib/lafcadio/util/UsStates.rb +0 -29
- data/lib/lafcadio/xml.rb +0 -2
@@ -1,25 +0,0 @@
|
|
1
|
-
module Lafcadio
|
2
|
-
module DomainComparable
|
3
|
-
include Comparable
|
4
|
-
|
5
|
-
# A DomainObject or DomainObjectProxy is compared by +objectType+ and by
|
6
|
-
# +pkId+.
|
7
|
-
def <=>(anOther)
|
8
|
-
if anOther.respond_to?( 'objectType' )
|
9
|
-
if self.objectType == anOther.objectType
|
10
|
-
self.pkId <=> anOther.pkId
|
11
|
-
else
|
12
|
-
self.objectType.name <=> anOther.objectType.name
|
13
|
-
end
|
14
|
-
else
|
15
|
-
nil
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def eql?(otherObj)
|
20
|
-
self == otherObj
|
21
|
-
end
|
22
|
-
|
23
|
-
def hash; "#{ self.class.name } #{ pkId }".hash; end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'lafcadio/objectStore/DomainComparable'
|
2
|
-
|
3
|
-
module Lafcadio
|
4
|
-
# The DomainObjectProxy is used when retrieving domain objects that are
|
5
|
-
# linked to other domain objects with LinkFields. In terms of +objectType+ and
|
6
|
-
# +pkId+, a DomainObjectProxy instance looks to the outside world like the
|
7
|
-
# domain object it's supposed to represent. It only retrieves its domain
|
8
|
-
# object from the database when member data is requested.
|
9
|
-
#
|
10
|
-
# In normal usage you will probably never manipulate a DomainObjectProxy
|
11
|
-
# directly, but you may discover it by accident by calling
|
12
|
-
# DomainObjectProxy#class (or DomainObject#class) instead of
|
13
|
-
# DomainObjectProxy#objectType (or DomainObjectProxy#objectType).
|
14
|
-
class DomainObjectProxy
|
15
|
-
include DomainComparable
|
16
|
-
|
17
|
-
attr_accessor :objectType, :pkId
|
18
|
-
|
19
|
-
def initialize(objectTypeOrDbObject, pkId = nil)
|
20
|
-
if pkId
|
21
|
-
@objectType = objectTypeOrDbObject
|
22
|
-
@pkId = pkId
|
23
|
-
elsif objectTypeOrDbObject.class < DomainObject
|
24
|
-
@dbObject = objectTypeOrDbObject
|
25
|
-
@d_obj_retrieve_time = Time.now
|
26
|
-
@objectType = @dbObject.class
|
27
|
-
@pkId = @dbObject.pkId
|
28
|
-
else
|
29
|
-
raise ArgumentError
|
30
|
-
end
|
31
|
-
@dbObject = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def getDbObject
|
35
|
-
object_store = ObjectStore.getObjectStore
|
36
|
-
if @dbObject.nil? || needs_refresh?
|
37
|
-
@dbObject = object_store.get(@objectType, @pkId)
|
38
|
-
@d_obj_retrieve_time = Time.now
|
39
|
-
|
40
|
-
end
|
41
|
-
@dbObject
|
42
|
-
end
|
43
|
-
|
44
|
-
def method_missing(methodId, *args)
|
45
|
-
getDbObject.send(methodId.id2name, *args)
|
46
|
-
end
|
47
|
-
|
48
|
-
def needs_refresh?
|
49
|
-
object_store = ObjectStore.getObjectStore
|
50
|
-
last_commit_time = object_store.last_commit_time( @objectType, @pkId )
|
51
|
-
!last_commit_time.nil? && last_commit_time > @d_obj_retrieve_time
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_s
|
55
|
-
getDbObject.to_s
|
56
|
-
end
|
57
|
-
|
58
|
-
def hash
|
59
|
-
getDbObject.hash
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'lafcadio/objectStore/DomainObjectInitError'
|
2
|
-
|
3
|
-
module Lafcadio
|
4
|
-
class DomainObjectSqlMaker #:nodoc:
|
5
|
-
attr_reader :bindValues
|
6
|
-
|
7
|
-
def initialize(obj); @obj = obj; end
|
8
|
-
|
9
|
-
def insertSQL(objectType)
|
10
|
-
fields = objectType.classFields
|
11
|
-
nameValuePairs = getNameValuePairs(objectType)
|
12
|
-
if objectType.isBasedOn?
|
13
|
-
nameValuePairs[objectType.sqlPrimaryKeyName] = 'LAST_INSERT_ID()'
|
14
|
-
end
|
15
|
-
fieldNameStr = nameValuePairs.keys.join ", "
|
16
|
-
fieldValueStr = nameValuePairs.values.join ", "
|
17
|
-
"insert into #{ objectType.tableName}(#{fieldNameStr}) " +
|
18
|
-
"values(#{fieldValueStr})"
|
19
|
-
end
|
20
|
-
|
21
|
-
def getNameValuePairs(objectType)
|
22
|
-
require 'lafcadio/util/QueueHash'
|
23
|
-
nameValues = []
|
24
|
-
objectType.classFields.each { |field|
|
25
|
-
value = @obj.send(field.name)
|
26
|
-
unless field.dbWillAutomaticallyWrite
|
27
|
-
nameValues << field.nameForSQL
|
28
|
-
nameValues <<(field.valueForSQL(value))
|
29
|
-
end
|
30
|
-
if field.bind_write?
|
31
|
-
@bindValues << value
|
32
|
-
end
|
33
|
-
}
|
34
|
-
QueueHash.new( *nameValues )
|
35
|
-
end
|
36
|
-
|
37
|
-
def updateSQL(objectType)
|
38
|
-
nameValueStrings = []
|
39
|
-
nameValuePairs = getNameValuePairs(objectType)
|
40
|
-
nameValuePairs.each { |key, value|
|
41
|
-
nameValueStrings << "#{key}=#{ value }"
|
42
|
-
}
|
43
|
-
allNameValues = nameValueStrings.join ', '
|
44
|
-
"update #{ objectType.tableName} set #{allNameValues} " +
|
45
|
-
"where #{ objectType.sqlPrimaryKeyName}=#{@obj.pkId}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def deleteSql(objectType)
|
49
|
-
"delete from #{ objectType.tableName} " +
|
50
|
-
"where #{ objectType.sqlPrimaryKeyName }=#{ @obj.pkId }"
|
51
|
-
end
|
52
|
-
|
53
|
-
def sqlStatements
|
54
|
-
statements = []
|
55
|
-
if @obj.errorMessages.size > 0
|
56
|
-
raise DomainObjectInitError, @obj.errorMessages, caller
|
57
|
-
end
|
58
|
-
@obj.class.selfAndConcreteSuperclasses.each { |objectType|
|
59
|
-
@bindValues = []
|
60
|
-
if @obj.pkId == nil
|
61
|
-
statement = insertSQL(objectType)
|
62
|
-
else
|
63
|
-
if @obj.delete
|
64
|
-
statement = deleteSql(objectType)
|
65
|
-
else
|
66
|
-
statement = updateSQL(objectType)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
statements << [statement, @bindValues]
|
70
|
-
}
|
71
|
-
statements.reverse
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,207 +0,0 @@
|
|
1
|
-
require 'lafcadio'
|
2
|
-
|
3
|
-
module Lafcadio
|
4
|
-
# The ObjectStore represents the database in a Lafcadio application.
|
5
|
-
#
|
6
|
-
# = Configuring the ObjectStore
|
7
|
-
# The ObjectStore depends on a few values being set correctly in the
|
8
|
-
# LafcadioConfig file:
|
9
|
-
# [dbuser] The database username.
|
10
|
-
# [dbpassword] The database password.
|
11
|
-
# [dbname] The database name.
|
12
|
-
# [dbhost] The database host.
|
13
|
-
#
|
14
|
-
# = Instantiating ObjectStore
|
15
|
-
# The ObjectStore is a ContextualService, meaning you can't get an instance by
|
16
|
-
# calling ObjectStore.new. Instead, you should call
|
17
|
-
# ObjectStore.getObjectStore. (Using a ContextualService makes it easier to
|
18
|
-
# make out the ObjectStore for unit tests: See ContextualService for more.)
|
19
|
-
#
|
20
|
-
# = Dynamic method calls
|
21
|
-
# ObjectStore uses reflection to provide a lot of convenience methods for
|
22
|
-
# querying domain objects in a number of ways.
|
23
|
-
# [ObjectStore#get< domain class > (pkId)]
|
24
|
-
# Retrieves one domain object by pkId. For example,
|
25
|
-
# ObjectStore#getUser( 100 )
|
26
|
-
# will return User 100.
|
27
|
-
# [ObjectStore#get< domain class >s (searchTerm, fieldName = nil)]
|
28
|
-
# Returns a collection of all instances of that domain class matching that
|
29
|
-
# search term. For example,
|
30
|
-
# ObjectStore#getProducts( aProductCategory )
|
31
|
-
# queries MySQL for all products that belong to that product category. You
|
32
|
-
# can omit +fieldName+ if +searchTerm+ is a non-nil domain object, and the
|
33
|
-
# field connecting the first domain class to the second is named after the
|
34
|
-
# domain class. (For example, the above line assumes that Product has a
|
35
|
-
# field named "productCategory".) Otherwise, it's best to include
|
36
|
-
# +fieldName+:
|
37
|
-
# ObjectStore#getUsers( "Jones", "lastName" )
|
38
|
-
#
|
39
|
-
# = Querying
|
40
|
-
# ObjectStore can also be used to generate complex, ad-hoc queries which
|
41
|
-
# emulate much of the functionality you'd get from writing the SQL yourself.
|
42
|
-
# Furthermore, these queries can be run against in-memory data stores, which
|
43
|
-
# is particularly useful for tests.
|
44
|
-
# date = Date.new( 2003, 1, 1 )
|
45
|
-
# ObjectStore#getInvoices { |invoice|
|
46
|
-
# Query.And( invoice.date.gte( date ), invoice.rate.equals( 10 ),
|
47
|
-
# invoice.hours.equals( 10 ) )
|
48
|
-
# }
|
49
|
-
# is the same as
|
50
|
-
# select * from invoices
|
51
|
-
# where (date >= '2003-01-01' and rate = 10 and hours = 10)
|
52
|
-
# See lafcadio/query.rb for more.
|
53
|
-
#
|
54
|
-
# = SQL Logging
|
55
|
-
# Lafcadio uses log4r to log all of its SQL statements. The simplest way to
|
56
|
-
# turn on logging is to set the following values in the LafcadioConfig file:
|
57
|
-
# [logSql] Should be set to "y" to turn on logging.
|
58
|
-
# [logdir] The directory where log files should be written. Required if
|
59
|
-
# +logSql+ is "y"
|
60
|
-
# [sqlLogFile] The name of the file (not including its directory) where SQL
|
61
|
-
# should be logged. Default is "sql".
|
62
|
-
#
|
63
|
-
# = Triggers
|
64
|
-
# Domain classes can be set to fire triggers either before or after commits.
|
65
|
-
# Since these triggers are executed in Ruby, they're easy to test. See
|
66
|
-
# DomainObject#preCommitTrigger and DomainObject#postCommitTrigger for more.
|
67
|
-
class ObjectStore < ContextualService
|
68
|
-
def ObjectStore.setDbName(dbName) #:nodoc:
|
69
|
-
DbBridge.setDbName dbName
|
70
|
-
end
|
71
|
-
|
72
|
-
def initialize(context, dbBridge = nil) #:nodoc:
|
73
|
-
super context
|
74
|
-
@dbBridge = dbBridge == nil ? DbBridge.new : dbBridge
|
75
|
-
@cache = ObjectStore::Cache.new( @dbBridge )
|
76
|
-
end
|
77
|
-
|
78
|
-
# Commits a domain object to the database. You can also simply call
|
79
|
-
# myDomainObject.commit
|
80
|
-
def commit(dbObject)
|
81
|
-
require 'lafcadio/objectStore/Committer'
|
82
|
-
committer = Committer.new dbObject, @dbBridge
|
83
|
-
committer.execute
|
84
|
-
updateCacheAfterCommit( committer )
|
85
|
-
end
|
86
|
-
|
87
|
-
# Flushes one domain object from its cache.
|
88
|
-
def flush(dbObject)
|
89
|
-
@cache.flush dbObject
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns the domain object corresponding to the domain class and pkId.
|
93
|
-
def get(objectType, pkId)
|
94
|
-
query = Query.new objectType, pkId
|
95
|
-
@cache.getByQuery( query )[0] ||
|
96
|
-
( raise( DomainObjectNotFoundError,
|
97
|
-
"Can't find #{objectType} #{pkId}", caller ) )
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns all domain objects for the given domain class.
|
101
|
-
def getAll(objectType)
|
102
|
-
query = Query.new( objectType )
|
103
|
-
@cache.getByQuery( query )
|
104
|
-
end
|
105
|
-
|
106
|
-
# Returns the DbBridge; this is useful in case you need to use raw SQL for a
|
107
|
-
# specific query.
|
108
|
-
def getDbBridge; @dbBridge; end
|
109
|
-
|
110
|
-
def getFiltered(objectTypeName, searchTerm, fieldName = nil) #:nodoc:
|
111
|
-
require 'lafcadio/query/Link'
|
112
|
-
objectType = DomainObject.getObjectTypeFromString objectTypeName
|
113
|
-
unless fieldName
|
114
|
-
fieldName = searchTerm.objectType.bareName
|
115
|
-
fieldName = fieldName.decapitalize
|
116
|
-
end
|
117
|
-
if searchTerm.class <= DomainObject
|
118
|
-
condition = Query::Link.new(fieldName, searchTerm, objectType)
|
119
|
-
else
|
120
|
-
condition = Query::Equals.new(fieldName, searchTerm, objectType)
|
121
|
-
end
|
122
|
-
getSubset( condition )
|
123
|
-
end
|
124
|
-
|
125
|
-
def getMapMatch(objectType, mapped) #:nodoc:
|
126
|
-
fieldName = mapped.objectType.bareName.decapitalize
|
127
|
-
Query::Equals.new(fieldName, mapped, objectType)
|
128
|
-
end
|
129
|
-
|
130
|
-
def getMapObject(objectType, map1, map2) #:nodoc:
|
131
|
-
require 'lafcadio/query/CompoundCondition'
|
132
|
-
unless map1 && map2
|
133
|
-
raise ArgumentError,
|
134
|
-
"ObjectStore#getMapObject needs two non-nil keys", caller
|
135
|
-
end
|
136
|
-
mapMatch1 = getMapMatch objectType, map1
|
137
|
-
mapMatch2 = getMapMatch objectType, map2
|
138
|
-
condition = Query::CompoundCondition.new mapMatch1, mapMatch2
|
139
|
-
getSubset(condition)[0]
|
140
|
-
end
|
141
|
-
|
142
|
-
def getMapped(searchTerm, resultTypeName) #:nodoc:
|
143
|
-
resultType = DomainObject.getObjectTypeFromString resultTypeName
|
144
|
-
coll = []
|
145
|
-
firstTypeName = searchTerm.class.bareName
|
146
|
-
secondTypeName = resultType.bareName
|
147
|
-
mapTypeName = firstTypeName + secondTypeName
|
148
|
-
getFiltered(mapTypeName, searchTerm).each { |mapObj|
|
149
|
-
coll << mapObj.send( resultType.name.decapitalize )
|
150
|
-
}
|
151
|
-
coll
|
152
|
-
end
|
153
|
-
|
154
|
-
# Retrieves the maximum value across all instances of one domain class.
|
155
|
-
# ObjectStore#getMax( Client )
|
156
|
-
# returns the highest +pkId+ in the +clients+ table.
|
157
|
-
# ObjectStore#getMax( Invoice, "rate" )
|
158
|
-
# will return the highest rate for all invoices.
|
159
|
-
def getMax( domain_class, field_name = nil )
|
160
|
-
query = Query::Max.new( domain_class, field_name )
|
161
|
-
@dbBridge.group_query( query ).only
|
162
|
-
end
|
163
|
-
|
164
|
-
# Retrieves a collection of domain objects by +pkId+.
|
165
|
-
# ObjectStore#getObjects( Clients, [ 1, 2, 3 ] )
|
166
|
-
def getObjects(objectType, pkIds)
|
167
|
-
require 'lafcadio/query/In'
|
168
|
-
condition = Query::In.new('pkId', pkIds, objectType)
|
169
|
-
getSubset condition
|
170
|
-
end
|
171
|
-
|
172
|
-
def getSubset(conditionOrQuery) #:nodoc:
|
173
|
-
if conditionOrQuery.class <= Query::Condition
|
174
|
-
condition = conditionOrQuery
|
175
|
-
query = Query.new condition.objectType, condition
|
176
|
-
else
|
177
|
-
query = conditionOrQuery
|
178
|
-
end
|
179
|
-
@cache.getByQuery( query )
|
180
|
-
end
|
181
|
-
|
182
|
-
def last_commit_time( domain_class, pkId ) #:nodoc:
|
183
|
-
@cache.last_commit_time( domain_class, pkId )
|
184
|
-
end
|
185
|
-
|
186
|
-
def method_missing(methodId, *args) #:nodoc:
|
187
|
-
proc = block_given? ? ( proc { |obj| yield( obj ) } ) : nil
|
188
|
-
dispatch = MethodDispatch.new( methodId, proc, *args )
|
189
|
-
self.send( dispatch.symbol, *dispatch.args )
|
190
|
-
end
|
191
|
-
|
192
|
-
# Caches one domain object.
|
193
|
-
def set(dbObject)
|
194
|
-
@cache.save dbObject
|
195
|
-
end
|
196
|
-
|
197
|
-
def updateCacheAfterCommit( committer ) #:nodoc:
|
198
|
-
if committer.commitType == Committer::UPDATE ||
|
199
|
-
committer.commitType == Committer::INSERT
|
200
|
-
set( committer.dbObject )
|
201
|
-
elsif committer.commitType == Committer::DELETE
|
202
|
-
@cache.flush( committer.dbObject )
|
203
|
-
end
|
204
|
-
@cache.set_commit_time( committer.dbObject )
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
@@ -1,207 +0,0 @@
|
|
1
|
-
require 'lafcadio'
|
2
|
-
|
3
|
-
module Lafcadio
|
4
|
-
# The ObjectStore represents the database in a Lafcadio application.
|
5
|
-
#
|
6
|
-
# = Configuring the ObjectStore
|
7
|
-
# The ObjectStore depends on a few values being set correctly in the
|
8
|
-
# LafcadioConfig file:
|
9
|
-
# [dbuser] The database username.
|
10
|
-
# [dbpassword] The database password.
|
11
|
-
# [dbname] The database name.
|
12
|
-
# [dbhost] The database host.
|
13
|
-
#
|
14
|
-
# = Instantiating ObjectStore
|
15
|
-
# The ObjectStore is a ContextualService, meaning you can't get an instance by
|
16
|
-
# calling ObjectStore.new. Instead, you should call
|
17
|
-
# ObjectStore.getObjectStore. (Using a ContextualService makes it easier to
|
18
|
-
# make out the ObjectStore for unit tests: See ContextualService for more.)
|
19
|
-
#
|
20
|
-
# = Dynamic method calls
|
21
|
-
# ObjectStore uses reflection to provide a lot of convenience methods for
|
22
|
-
# querying domain objects in a number of ways.
|
23
|
-
# [ObjectStore#get< domain class > (pkId)]
|
24
|
-
# Retrieves one domain object by pkId. For example,
|
25
|
-
# ObjectStore#getUser( 100 )
|
26
|
-
# will return User 100.
|
27
|
-
# [ObjectStore#get< domain class >s (searchTerm, fieldName = nil)]
|
28
|
-
# Returns a collection of all instances of that domain class matching that
|
29
|
-
# search term. For example,
|
30
|
-
# ObjectStore#getProducts( aProductCategory )
|
31
|
-
# queries MySQL for all products that belong to that product category. You
|
32
|
-
# can omit +fieldName+ if +searchTerm+ is a non-nil domain object, and the
|
33
|
-
# field connecting the first domain class to the second is named after the
|
34
|
-
# domain class. (For example, the above line assumes that Product has a
|
35
|
-
# field named "productCategory".) Otherwise, it's best to include
|
36
|
-
# +fieldName+:
|
37
|
-
# ObjectStore#getUsers( "Jones", "lastName" )
|
38
|
-
#
|
39
|
-
# = Querying
|
40
|
-
# ObjectStore can also be used to generate complex, ad-hoc queries which
|
41
|
-
# emulate much of the functionality you'd get from writing the SQL yourself.
|
42
|
-
# Furthermore, these queries can be run against in-memory data stores, which
|
43
|
-
# is particularly useful for tests.
|
44
|
-
# date = Date.new( 2003, 1, 1 )
|
45
|
-
# ObjectStore#getInvoices { |invoice|
|
46
|
-
# Query.And( invoice.date.gte( date ), invoice.rate.equals( 10 ),
|
47
|
-
# invoice.hours.equals( 10 ) )
|
48
|
-
# }
|
49
|
-
# is the same as
|
50
|
-
# select * from invoices
|
51
|
-
# where (date >= '2003-01-01' and rate = 10 and hours = 10)
|
52
|
-
# See lafcadio/query.rb for more.
|
53
|
-
#
|
54
|
-
# = SQL Logging
|
55
|
-
# Lafcadio uses log4r to log all of its SQL statements. The simplest way to
|
56
|
-
# turn on logging is to set the following values in the LafcadioConfig file:
|
57
|
-
# [logSql] Should be set to "y" to turn on logging.
|
58
|
-
# [logdir] The directory where log files should be written. Required if
|
59
|
-
# +logSql+ is "y"
|
60
|
-
# [sqlLogFile] The name of the file (not including its directory) where SQL
|
61
|
-
# should be logged. Default is "sql".
|
62
|
-
#
|
63
|
-
# = Triggers
|
64
|
-
# Domain classes can be set to fire triggers either before or after commits.
|
65
|
-
# Since these triggers are executed in Ruby, they're easy to test. See
|
66
|
-
# DomainObject#preCommitTrigger and DomainObject#postCommitTrigger for more.
|
67
|
-
class ObjectStore < ContextualService
|
68
|
-
def ObjectStore.setDbName(dbName) #:nodoc:
|
69
|
-
DbBridge.setDbName dbName
|
70
|
-
end
|
71
|
-
|
72
|
-
def initialize(context, dbBridge = nil) #:nodoc:
|
73
|
-
super context
|
74
|
-
@dbBridge = dbBridge == nil ? DbBridge.new : dbBridge
|
75
|
-
@cache = ObjectStore::Cache.new( @dbBridge )
|
76
|
-
end
|
77
|
-
|
78
|
-
# Commits a domain object to the database. You can also simply call
|
79
|
-
# myDomainObject.commit
|
80
|
-
def commit(dbObject)
|
81
|
-
require 'lafcadio/objectStore/Committer'
|
82
|
-
committer = Committer.new dbObject, @dbBridge
|
83
|
-
committer.execute
|
84
|
-
updateCacheAfterCommit( committer )
|
85
|
-
end
|
86
|
-
|
87
|
-
# Flushes one domain object from its cache.
|
88
|
-
def flush(dbObject)
|
89
|
-
@cache.flush dbObject
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns the domain object corresponding to the domain class and pkId.
|
93
|
-
def get(objectType, pkId)
|
94
|
-
query = Query.new objectType, pkId
|
95
|
-
@cache.getByQuery( query )[0] ||
|
96
|
-
( raise( DomainObjectNotFoundError,
|
97
|
-
"Can't find #{objectType} #{pkId}", caller ) )
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns all domain objects for the given domain class.
|
101
|
-
def getAll(objectType)
|
102
|
-
query = Query.new( objectType )
|
103
|
-
@cache.getByQuery( query )
|
104
|
-
end
|
105
|
-
|
106
|
-
# Returns the DbBridge; this is useful in case you need to use raw SQL for a
|
107
|
-
# specific query.
|
108
|
-
def getDbBridge; @dbBridge; end
|
109
|
-
|
110
|
-
def getFiltered(objectTypeName, searchTerm, fieldName = nil) #:nodoc:
|
111
|
-
require 'lafcadio/query/Link'
|
112
|
-
objectType = DomainObject.getObjectTypeFromString objectTypeName
|
113
|
-
unless fieldName
|
114
|
-
fieldName = searchTerm.objectType.bareName
|
115
|
-
fieldName = fieldName.decapitalize
|
116
|
-
end
|
117
|
-
if searchTerm.class <= DomainObject
|
118
|
-
condition = Query::Link.new(fieldName, searchTerm, objectType)
|
119
|
-
else
|
120
|
-
condition = Query::Equals.new(fieldName, searchTerm, objectType)
|
121
|
-
end
|
122
|
-
getSubset( condition )
|
123
|
-
end
|
124
|
-
|
125
|
-
def getMapMatch(objectType, mapped) #:nodoc:
|
126
|
-
fieldName = mapped.objectType.bareName.decapitalize
|
127
|
-
Query::Equals.new(fieldName, mapped, objectType)
|
128
|
-
end
|
129
|
-
|
130
|
-
def getMapObject(objectType, map1, map2) #:nodoc:
|
131
|
-
require 'lafcadio/query/CompoundCondition'
|
132
|
-
unless map1 && map2
|
133
|
-
raise ArgumentError,
|
134
|
-
"ObjectStore#getMapObject needs two non-nil keys", caller
|
135
|
-
end
|
136
|
-
mapMatch1 = getMapMatch objectType, map1
|
137
|
-
mapMatch2 = getMapMatch objectType, map2
|
138
|
-
condition = Query::CompoundCondition.new mapMatch1, mapMatch2
|
139
|
-
getSubset(condition)[0]
|
140
|
-
end
|
141
|
-
|
142
|
-
def getMapped(searchTerm, resultTypeName) #:nodoc:
|
143
|
-
resultType = DomainObject.getObjectTypeFromString resultTypeName
|
144
|
-
coll = []
|
145
|
-
firstTypeName = searchTerm.class.bareName
|
146
|
-
secondTypeName = resultType.bareName
|
147
|
-
mapTypeName = firstTypeName + secondTypeName
|
148
|
-
getFiltered(mapTypeName, searchTerm).each { |mapObj|
|
149
|
-
coll << mapObj.send( resultType.name.decapitalize )
|
150
|
-
}
|
151
|
-
coll
|
152
|
-
end
|
153
|
-
|
154
|
-
# Retrieves the maximum value across all instances of one domain class.
|
155
|
-
# ObjectStore#getMax( Client )
|
156
|
-
# returns the highest +pkId+ in the +clients+ table.
|
157
|
-
# ObjectStore#getMax( Invoice, "rate" )
|
158
|
-
# will return the highest rate for all invoices.
|
159
|
-
def getMax( domain_class, field_name = 'pkId' )
|
160
|
-
query = Query::Max.new( domain_class, field_name )
|
161
|
-
@dbBridge.group_query( query ).only
|
162
|
-
end
|
163
|
-
|
164
|
-
# Retrieves a collection of domain objects by +pkId+.
|
165
|
-
# ObjectStore#getObjects( Clients, [ 1, 2, 3 ] )
|
166
|
-
def getObjects(objectType, pkIds)
|
167
|
-
require 'lafcadio/query/In'
|
168
|
-
condition = Query::In.new('pkId', pkIds, objectType)
|
169
|
-
getSubset condition
|
170
|
-
end
|
171
|
-
|
172
|
-
def getSubset(conditionOrQuery) #:nodoc:
|
173
|
-
if conditionOrQuery.class <= Query::Condition
|
174
|
-
condition = conditionOrQuery
|
175
|
-
query = Query.new condition.objectType, condition
|
176
|
-
else
|
177
|
-
query = conditionOrQuery
|
178
|
-
end
|
179
|
-
@cache.getByQuery( query )
|
180
|
-
end
|
181
|
-
|
182
|
-
def last_commit_time( domain_class, pkId ) #:nodoc:
|
183
|
-
@cache.last_commit_time( domain_class, pkId )
|
184
|
-
end
|
185
|
-
|
186
|
-
def method_missing(methodId, *args) #:nodoc:
|
187
|
-
proc = block_given? ? ( proc { |obj| yield( obj ) } ) : nil
|
188
|
-
dispatch = MethodDispatch.new( methodId, proc, *args )
|
189
|
-
self.send( dispatch.symbol, *dispatch.args )
|
190
|
-
end
|
191
|
-
|
192
|
-
# Caches one domain object.
|
193
|
-
def set(dbObject)
|
194
|
-
@cache.save dbObject
|
195
|
-
end
|
196
|
-
|
197
|
-
def updateCacheAfterCommit( committer ) #:nodoc:
|
198
|
-
if committer.commitType == Committer::UPDATE ||
|
199
|
-
committer.commitType == Committer::INSERT
|
200
|
-
set( committer.dbObject )
|
201
|
-
elsif committer.commitType == Committer::DELETE
|
202
|
-
@cache.flush( committer.dbObject )
|
203
|
-
end
|
204
|
-
@cache.set_commit_time( committer.dbObject )
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|