Class: Lafcadio::ObjectStore
- Inherits:
-
ContextualService::Service
- Object
- ContextualService::Service
- Lafcadio::ObjectStore
- Defined in:
- lib/lafcadio/objectStore.rb,
lib/lafcadio/mock.rb
Overview
The ObjectStore represents the database in a Lafcadio application.
Configuring the ObjectStore
The ObjectStore depends on a few values being set correctly in the LafcadioConfig file:
- dbuser
-
The database username.
- dbpassword
-
The database password.
- dbname
-
The database name.
- dbhost
-
The database host.
Instantiating ObjectStore
You can’t get an instance of ObjectStore by calling ObjectStore.new. Instead, you should call ObjectStore.get_object_store.
Dynamic method calls
ObjectStore uses reflection to provide a lot of convenience methods for querying domain objects in a number of ways.
- ObjectStore#< domain class >( pk_id )
-
Retrieves one domain object by pk_id. For example,
ObjectStore#user( 100 )
will return User 100. Note that you can also just user DomainObject.[]:
User[100]
- ObjectStore#< plural of domain class >( searchTerm, fieldName = nil )
-
Returns a collection of all instances of that domain class matching that search term. For example,
ObjectStore#products( a_product_category )
queries MySQL for all products that belong to that product category. You can omit
fieldName
ifsearchTerm
is a non-nil domain object, and the field connecting the first domain class to the second is named after the domain class. (For example, the above line assumes that Product has a field named “product_category”.) Otherwise, it’s best to includefieldName
:ObjectStore#users( "Jones", "lastName" )
Note that these can also be accessed through DomainObject.get:
Product.get( a_product_category ) User.get( "Jones", "lastName" )
Querying
ObjectStore can also be used to generate complex, ad-hoc queries which emulate much of the functionality you’d get from writing the SQL yourself. Furthermore, these queries can be run against in-memory data stores, which is particularly useful for tests.
date = Date.new( 2003, 1, 1 )
ObjectStore#invoices { |invoice|
invoice.date.gte( date ) & invoice.rate.equals( 10 ) &
invoice.hours.equals( 10 )
}
is the same as
select * from invoices
where (date >= '2003-01-01' and rate = 10 and hours = 10)
Note that you can also use DomainObject.get:
Invoice.get { |invoice|
invoice.date.gte( date ) & invoice.rate.equals( 10 ) &
invoice.hours.equals( 10 )
}
See lafcadio/query.rb for more on the query inference syntax.
SQL Logging
Lafcadio uses log4r to log all of its SQL statements. The simplest way to turn on logging is to set the following values in the LafcadioConfig file:
- logSql
-
Should be set to “y” to turn on logging.
- logdir
-
The directory where log files should be written. Required if
logSql
is “y” - sqlLogFile
-
The name of the file (not including its directory) where SQL should be logged. Default is “sql”.
Triggers
Domain classes can be set to fire triggers either before or after commits. Since these triggers are executed in Ruby, they’re easy to test. See DomainObject#pre_commit_trigger and DomainObject#post_commit_trigger for more.
Direct Known Subclasses
Defined Under Namespace
Classes: Cache, CommitSqlStatementsAndBinds, DbBridge, DbConnection, MethodDispatch, MockDbBridge, RollbackError, SqlToRubyValues
Constant Summary collapse
- @@db_bridge =
nil
- @@db_type =
'Mysql'
Class Method Summary collapse
-
.db_bridge ⇒ Object
Returns the DbBridge; this is useful in case you need to use raw SQL for a specific query.
- .db_name=(dbName) ⇒ Object
- .db_type ⇒ Object
- .db_type=(dbt) ⇒ Object
-
.mock? ⇒ Boolean
Returns true if the current stored instance is a MockObjectStore.
Instance Method Summary collapse
-
#all(domain_class, opts = {}) ⇒ Object
Returns all domain objects for the given domain class.
-
#db_bridge ⇒ Object
Returns the DbBridge; this is useful in case you need to use raw SQL for a specific query.
-
#get(domain_class, pk_id) ⇒ Object
Returns the domain object corresponding to the domain class and pk_id.
-
#get_map_object(domain_class, map1, map2) ⇒ Object
:nodoc:.
-
#group_query(query) ⇒ Object
:nodoc:.
-
#initialize ⇒ ObjectStore
constructor
:nodoc:.
-
#max(domain_class, field_name = 'pk_id') ⇒ Object
Retrieves the maximum value across all instances of one domain class.
-
#method_missing(methodId, *args) ⇒ Object
:nodoc:.
-
#mock? ⇒ Boolean
:nodoc:.
-
#query(conditionOrQuery) ⇒ Object
Passes a query and selects with it.
-
#respond_to?(symbol, include_private = false) ⇒ Boolean
:nodoc:.
-
#transaction(&action) ⇒ Object
As long as the underlying database table sorts transactions, you can use this to run transactional logic.
Constructor Details
#initialize ⇒ ObjectStore
:nodoc:
168 169 170 |
# File 'lib/lafcadio/objectStore.rb', line 168 def initialize #:nodoc: @cache = ObjectStore::Cache.new self.class.db_bridge end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(methodId, *args) ⇒ Object
:nodoc:
222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/lafcadio/objectStore.rb', line 222 def method_missing(methodId, *args) #:nodoc: if [ :commit, :flush, :last_commit_time ].include?( methodId ) @cache.send( methodId, *args ) else proc = block_given? ? ( proc { |obj| yield( obj ) } ) : nil dispatch = MethodDispatch.new( methodId, proc, *args ) if dispatch.symbol dispatch.dispatch self else super end end end |
Class Method Details
.db_bridge ⇒ Object
Returns the DbBridge; this is useful in case you need to use raw SQL for a specific query.
155 |
# File 'lib/lafcadio/objectStore.rb', line 155 def self.db_bridge; @@db_bridge ||= DbBridge.new; end |
.db_name=(dbName) ⇒ Object
157 158 159 |
# File 'lib/lafcadio/objectStore.rb', line 157 def self.db_name= (dbName) DbConnection.db_name= dbName end |
.db_type ⇒ Object
161 |
# File 'lib/lafcadio/objectStore.rb', line 161 def self.db_type; @@db_type; end |
.db_type=(dbt) ⇒ Object
163 |
# File 'lib/lafcadio/objectStore.rb', line 163 def self.db_type=( dbt ); @@db_type = dbt; end |
.mock? ⇒ Boolean
Returns true if the current stored instance is a MockObjectStore.
166 |
# File 'lib/lafcadio/objectStore.rb', line 166 def self.mock?; get_object_store.mock?; end |
Instance Method Details
#all(domain_class, opts = {}) ⇒ Object
Returns all domain objects for the given domain class.
173 174 175 |
# File 'lib/lafcadio/objectStore.rb', line 173 def all( domain_class, opts = {} ) @cache.get_by_query( Query.new( domain_class, opts ) ) end |
#db_bridge ⇒ Object
Returns the DbBridge; this is useful in case you need to use raw SQL for a specific query.
179 |
# File 'lib/lafcadio/objectStore.rb', line 179 def db_bridge; @cache.db_bridge; end |
#get(domain_class, pk_id) ⇒ Object
Returns the domain object corresponding to the domain class and pk_id.
182 183 184 185 186 187 188 189 190 |
# File 'lib/lafcadio/objectStore.rb', line 182 def get( domain_class, pk_id ) qry = Query.new( domain_class, :pk_id => pk_id ) @cache.get_by_query( qry ).first or ( raise( DomainObjectNotFoundError, "Can't find #{domain_class} #{pk_id}", caller ) ) end |
#get_map_object(domain_class, map1, map2) ⇒ Object
:nodoc:
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/lafcadio/objectStore.rb', line 192 def get_map_object( domain_class, map1, map2 ) #:nodoc: unless map1 && map2 raise ArgumentError, "ObjectStore#get_map_object needs two non-nil keys", caller end query = Query.infer( domain_class ) { |dobj| dobj.send( map1.domain_class.basename.camel_case_to_underscore ).equals( map1 ) & dobj.send( map2.domain_class.basename.camel_case_to_underscore ).equals( map2 ) } query( query ).first end |
#group_query(query) ⇒ Object
:nodoc:
208 209 210 |
# File 'lib/lafcadio/objectStore.rb', line 208 def group_query( query ) #:nodoc: @cache.group_query( query ) end |
#max(domain_class, field_name = 'pk_id') ⇒ Object
Retrieves the maximum value across all instances of one domain class.
ObjectStore#max( Client )
returns the highest pk_id
in the clients
table.
ObjectStore#max( Invoice, "rate" )
will return the highest rate for all invoices.
217 218 219 220 |
# File 'lib/lafcadio/objectStore.rb', line 217 def max( domain_class, field_name = 'pk_id' ) qry = Query::Max.new( domain_class, field_name ) @cache.group_query( qry ).only[:max] end |
#mock? ⇒ Boolean
:nodoc:
236 237 238 |
# File 'lib/lafcadio/objectStore.rb', line 236 def mock? #:nodoc: false end |
#query(conditionOrQuery) ⇒ Object
Passes a query and selects with it.
qry = Query.infer( User ) { |user| user.fname.equals( 'Francis' ) }
francises = ObjectStore.get_object_store.query( qry )
243 244 245 246 247 248 249 250 251 |
# File 'lib/lafcadio/objectStore.rb', line 243 def query(conditionOrQuery) if conditionOrQuery.class <= Query::Condition condition = conditionOrQuery query = Query.new( condition.domain_class, :condition => condition ) else query = conditionOrQuery end @cache.get_by_query( query ) end |
#respond_to?(symbol, include_private = false) ⇒ Boolean
:nodoc:
253 254 255 256 257 258 259 |
# File 'lib/lafcadio/objectStore.rb', line 253 def respond_to?( symbol, include_private = false ) #:nodoc: if MethodDispatch.new( symbol ).symbol true else super end end |
#transaction(&action) ⇒ Object
As long as the underlying database table sorts transactions, you can use this to run transactional logic. These transactions will auto commit at the end of the block, and can be rolled back.
ObjectStore.get_object_store.transaction do |tr|
Client.new( 'name' => 'Big Co.' ).commit
tr.rollback
end # the client will not be saved to the DB
268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/lafcadio/objectStore.rb', line 268 def transaction( &action ) old_cache = @cache @cache = @cache.transactional_clone begin @cache.transaction action rescue err_to_raise = $! @cache.rollback unless $!.is_a? RollbackError @cache = old_cache raise err_to_raise unless $!.is_a? RollbackError end end |