| Path: | highcrest/persistence.rb |
| Last Update: | Wed May 26 14:21:41 GMT Daylight Time 2004 |
This library can be included to add database persistence to a domain class. The module:
Assuming the table: CREATE TABLE FOO (ID VARCHAR(32) PRIMARY KEY, DESCRIPTION VARCHAR(1000))
Require the library for your DBD driver
require 'highcrest/persistence/oci8'
==>true
Declare a persistent class
class Foo
include Highcrest::Persistence
attr_accessor :id, :description
end
==>nil
Create and insert a new object with generated key
begin
foo = Foo.new
foo.description = 'I am a Foo'
foo.replace!
Foo.dbh.commit
foo
rescue Exception => ex
Foo.dbh.rollback
raise ex
end
==>#<Foo:0x31ad5a8 @description="I am a Foo", @id=105681042.0, @optimistic_values={"ID"=>105681042.0, "DESCRIPTION"=>"I am a Foo"}>
Create and insert a new object with assigned key
begin
foo2 = Foo.new
foo2.id = 'key'
foo2.description = 'I am a Foo'
foo2.insert!
Foo.dbh.commit
foo2
rescue Exception => ex
Foo.dbh.rollback
raise ex
end
==>#<Foo:0x31a1d40 @description="I am a Foo", @id="key", @optimistic_values={"ID"=>"key", "DESCRIPTION"=>"I am a Foo"}>
Retrieve and update existing object
begin
foo2 = Foo.read 'key'
foo2.description = 'I am a Foo too'
foo2.replace!
Foo.dbh.commit
foo
rescue Exception => ex
Foo.dbh.rollback
raise ex
end
==>#<Foo:0x31ad5a8 @description="I am a Foo", @id=105681042.0, @optimistic_values={"ID"=>105681042.0, "DESCRIPTION"=>"I am a Foo"}>
Delete an object
begin
foo.delete!
Foo.dbh.commit
foo
rescue Exception => ex
Foo.dbh.rollback
raise ex
end
==>#<Foo:0x31ad5a8 @description="I am a Foo", @id=105681042.0, @optimistic_values=nil>
Search for lightweight DBI rows with partial match
begin
rows = Foo.search 'description'=>'I am a Foo'
rescue Exception => ex
Foo.dbh.rollback
raise ex
end
==>[["key", "I am a Foo too"]]
I recommend that you create a patch file to redefine these methods, and also define any type-conversions required by your DBD driver. See highcrest/persistence for some oracle examples.
I assume that transactions are controlled from a higher-level tier in your application. You are responsible for setting the commit policy on your database handle, and calling commit or rollback.
(Of course you can easily redefine the main CRUD methods to be transactional if that fits your requirements.)
FIXME Column- and type conversions, search-conversions, sql generators.
Updates and deletes are automatically subject to optimistic locking. Whenever an object is loaded from the database, or successfully saved, a hash of the database’s current values for this record is created. Subsequent attempts to update the database are subject to a where clause based on those values. If another user has updated the record in the meantime, then no rows will be updated and a RecordNotFoundError will be thrown.
LOBs and LONGs are not included in optimistic locking tests.
LONGs are supported if the underlying DBD driver supports them.
LOBs can also be supported, but write_lobs, from_type_LOB and to_type_LOB methods must all be defined. See highcrest/persistence/oci8.rb for an oracle solution.
Note however that this module is not an appropriate solution for very large objects, because the entire object is read into memory. In scenarios where this is impractical, I suggest that you stream data from the persistent store to the presentation layer without going through an object model.
See highcrest/persistence for a set of patches for use with Oracle DBD drivers. See highcrest/persistence/example for some sample class files. See highcrest/persistence/test for a fairly comprehensive set of unit tests. And see recipes.txt for a set of code-fragments for common scenarios.
Copyright 2004 Graham Robert Jenkins
I don’t mind what you do with this code as long as you acknowledge my contribution.