| Class | Lafcadio::DomainObject |
| In: |
lafcadio/domain.rb
lafcadio/test.rb |
| Parent: | Object |
All classes that correspond to a table in the database need to be children of DomainObject.
There are three ways to define the fields of a DomainObject subclass.
class User < Lafcadio::DomainObject
string 'lastName'
email 'email'
string 'password'
date 'birthday'
end
These can also be pluralized:
class User < Lafcadio::DomainObject
strings 'lastName', 'password'
email 'email'
date 'birthday'
end
The class methods you can use are binary, boolean, date, date_time, domain_object, email, enum, float, integer, month, state, string, text_list. These correspond to BinaryField, BooleanField, DateField, DateTimeField, DomainObjectField, EmailField, EnumField, FloatField, IntegerField, MonthField, StateField, StringField, and TextListField, respectively. Consult their individual RDoc entries for more on how to parameterize them through the class methods.
class User < DomainObject
def User.get_class_fields
fields = super
fields << StringField.new(self, 'firstName')
fields << StringField.new(self, 'lastName')
fields << StringField.new(self, 'email')
fields << StringField.new(self, 'password')
fields << DateField.new(self, 'birthday')
fields
end
end
This method is probably not worth the trouble unless you end up defining your own field classes for some reason.
<lafcadio_class_definition name="User">
<field name="lastName" class="StringField"/>
<field name="email" class="StringField"/>
<field name="password" class="StringField"/>
<field name="birthday" class="DateField"/>
</lafcadio_class_definition>
Once your fields are defined, you can create an instance by passing in a hash of field names and values.
john = User.new(
:firstName => 'John', :lastName => 'Doe',
:email => 'john.doe@email.com', :password => 'my_password',
:birthday => Date.new( 1979, 1, 15 )
)
You can read and write these fields like normal instance attributes.
john.email # => 'john.doe@email.com' john.email = 'john.doe@mail.email.com'
If your domain class has fields that refer to other domain classes, or even to another row in the same table, you can use a DomainObjectField to express the relation.
class Message < Lafcadio::DomainObject
strings 'subject', 'body'
domain_object User, 'author'
domain_object User, 'recipient'
date 'date_sent'
end
msg = Message.new(
:subject => 'hi there',
:body => 'You wanna go to the movies on Saturday?',
:author => john, :recipient => jane, :dateSent => Date.today
)
Lafcadio requires that each table has a numeric primary key. It assumes that this key is named pk_id in the database, though that can be overridden.
When you create a domain object by calling DomainObject.new, you should not assign a pk_id to the new instance. The pk_id will automatically be set when you commit the object by calling DomainObject#commit.
However, you may want to manually set pk_id when setting up a test case, so you can ensure that a domain object has a given primary key.
By default, Lafcadio assumes that every domain object is indexed by the field pk_id in the database schema. If you’re dealing with a table that uses a different field name, call DomainObject.sql_primary_key_name. However, you will always use pk_id in your Ruby code.
Lafcadio assumes that a domain class corresponds to a table whose name is the pluralized, lower-case, underscored version of the class name. A User class is assumed to be stored in a "users" table, while a ProductCategory class is assumed to be stored in a "product_categories" table. Call DomainObject.table_name to override this behavior.
class LegacyThing < Lafcadio::DomainObject
string 'some_field'
sql_primary_key_name 'some_legacy_id'
table_name 'some_legacy_table'
end
thing = LegacyThing[9909]
thing.pk_id # => 9909
Domain classes can inherit from other domain classes; they have all the fields of any concrete superclasses plus any new fields defined for themselves. You can use normal inheritance to define this:
class User < Lafcadio::DomainObject
...
end
class Administrator < User
...
end
Lafcadio assumes that each concrete class has a corresponding table, and that each table has a pk_id field that is used to match rows between different levels.
| delete | [R] | |
| field_values | [RW] | |
| fields_set | [RW] | |
| last_commit_type | [RW] |
Commits and returns a custom mock object of the given domain class. All the field values are set to defaults, except for the fields passed in through custom_args. This mock object will have a pk_id greater than 1, and each successive call to DomainObject.custom_mock will return an object with a unique pk_id.
This class method is only visible if you include lafcadio/test.rb.
class User < Lafcadio::DomainObject
strings :fname, :lname, :email
end
u1 = User.custom_mock
u1.fname # => 'test text'
u1.lname # => 'test text'
u1.email # => 'test text'
u1.pk_id # => probably 2, guaranteed to be greater than 1
u2 = User.custom_mock( 'fname' => 'Francis', 'lname' => 'Hwang' )
u2.fname # => 'Francis'
u2.lname # => 'Hwang'
u2.email # => 'test text'
u2.pk_id # => probably 3, guaranteed to not be u1.pk_id and to be
# greater than 1
Returns a hash of default arguments for mock instances of this domain class. DomainObject.default_mock uses exactly these arguments to create the default mock for a given domain class, and DomainObject.custom_mock overrides some of the field arguments based on its custom arguments.
By default this will retrieve simple values based on the field type:
You can override this method, if you like. However, it will probably be simpler just to call DomainObject.mock_value.
This class method is only visible if you include lafcadio/test.rb.
Sets a default setup hash for a field of a certain class. Useful for mapping domain classes with lots of fields and unusual field configurations.
class LotsOfBooleans < Lafcadio::DomainObject
default_field_setup_hash(
Lafcadio::BooleanField, { 'enum_type' => :capital_yes_no }
)
booleans 'this', 'that', 'the_other', 'and_another_one',
'this_one_too'
end
Commits and returns a mock object of the given domain class. All the field values are set to defaults. This mock object will have a pk_id of 1. Successive calls to DomainObject.default_mock will always return the same mock object.
This class method is only visible if you include lafcadio/test.rb.
class User < Lafcadio::DomainObject
strings :fname, :lname, :email
end
u1 = User.default_mock
u1.fname # => 'test text'
u1.lname # => 'test text'
u1.email # => 'test text'
u1.pk_id # => 1
Tests whether a given domain object exists.
User.exist?( 8280 ) # => returns true iff there's a User 8280
User.exist?( 'Hwang', :lastName ) # => returns true iff there's a User
# with the last name 'Hwang'
This class method has a few uses, depending on how you use it.
adult_hwangs = User.get { |user|
user.lastName.equals( 'Hwang' ) &
user.birthday.lte( Date.today - ( 365 * 18 ) )
}
See query.rb for more information about how to form these queries.
hwangs = User.get( 'Hwang', :lastName ) user123 = User.get( 123 ).first
num_users = User.get( :group => :count ).first[:count]
Returns an Array of ObjectField instances for this domain class, parsing them from XML if necessary. You can override this to define a domain class’ fields, though it will probably just be simpler to use one-line class methods instead.
Sets the mock value for the given field. These mock values are used in DomainObject.default_mock and DomainObject.custom_mock
This class method is only visible if you include lafcadio/test.rb.
class User < Lafcadio::DomainObject
strings :fname, :lname, :email
end
User.mock_value :fname, 'Bill'
User.mock_value :lname, 'Smith'
u1 = User.default_mock
u1.fname # => 'Bill'
u1.lname # => 'Smith'
u1.email # => 'test text'
u1.pk_id # => 1
Sets the mock value for the fields in hash. These mock values are used in DomainObject.default_mock and DomainObject.custom_mock
This class method is only visible if you include lafcadio/test.rb.
class User < Lafcadio::DomainObject
strings :fname, :lname, :email
end
User.mock_values { :fname => 'Bill', :lname => 'Smith' }
u1 = User.default_mock
u1.fname # => 'Bill'
u1.lname # => 'Smith'
u1.email # => 'test text'
u1.pk_id # => 1
field_hash should contain key-value associations for the different fields of this domain class. For example, instantiating a User class might look like:
User.new(
'firstNames' => 'John', 'lastName' => 'Doe',
'email' => 'john.doe@email.com', 'password' => 'l33t'
)
In normal usage any code you write that creates a domain object will not define the pk_id field. The system assumes that a domain object with an undefined pk_id has yet to be inserted into the database, and when you commit the domain object a pk_id will automatically be assigned.
If you’re creating mock objects for unit tests, you can explicitly set the pk_id to represent objects that already exist in the database.
Returns the only committed instance of the domain class. Will raise an IndexError if there are 0, or more than 1, domain objects.
the_one_user = User.only
If set_db_field_name is nil, this will return the sql name of the primary key. If set_db_field_name isn’t nil, it will set the sql name.
class User < Lafcadio::DomainObject
string 'firstNames'
end
User.sql_primary_key_name # => 'pk_id'
class User < Lafcadio::DomainObject
sql_primary_key_name 'some_other_id'
end
User.sql_primary_key_name # => 'some_other_id'
If set_table_name is nil, DomainObject.table_name will return the table name. Lafcadio assumes that a domain class corresponds to a table whose name is the pluralized, lower-case, underscored version of the class name. A User class is assumed to be stored in a "users" table, while a ProductCategory class is assumed to be stored in a "product_categories" table.
If set_table_name is not nil, this will set the table name.
class User < Lafcadio::DomainObject
string 'firstNames'
end
User.table_name # => 'users'
class User < Lafcadio::DomainObject
table_name 'some_table'
end
User.table_name # => 'some_table'
Set the delete value to true if you want this domain object to be deleted from the database during its next commit.
Returns the subclass of DomainObject that this instance represents. Because of the way that proxying works, clients should call this method instead of Object.class.
This template method is called after every commit. Subclasses can override it to ensure code is executed after a commit.
This template method is called before every commit. Subclasses can override it to ensure code is executed before a commit.
Updates a domain object and commits the changes to the database immediately.
user99 = User[99] user99.update!( :firstNames => 'Bill', :password => 'n3wp4ssw0rd' )
If you’re running against a MockObjectStore, this will verify each field and raise an error if there’s any invalid fields.