-
Notifications
You must be signed in to change notification settings - Fork 5
Active Row
activerow
is a hybrid implementation of the Active Record design pattern. Unlike ds_row
which typically represents an existing row, activerow
may not yet exist as a row in the data source. It can either be used stand alone or ad the parent parent type for your own types and expands on the functionality of ds_row
.
Rows returned from ds
can be cast as activerow
types (or other types based on it) like so:
with row #ds->rows(::activerow) do {
#row->isa(::activerow) // true
}
Or:
with row in #ds->rows(::product) do { // product inherits from activerow
#row->isa(::activerow) // true
}
This allows you to work with your own type definitions in an OOP fashion with minimal overhead and is one of the key strengths of the Datasource suite of tools.
You can also create new rows and objects like so:
local(product) = activerow(::store.product)
#product->save(
::brand = 'ACME',
::description = 'Example Product'
::price = 9.95
)
##Creators
The activerow
type can be created with the following creators:
-> oncreate(keyvalue::integer)
-> oncreate(keyvalue::string)
-> oncreate(keyvalues::pair,...morepairs)
-> oncreate(database.table::tag,...optionalkeys)
-> oncreate(ds::ds,...optionalkeys)
-> oncreate(row::ds_row)
####Configuration via Oncreate
Alternatively you can specific the database and table with the oncreate
methods like so:
local(product) = activerow(::store.product,#id)
Or:
local(product) = activerow(::store.product,::uuid = #uuid)
####Using oncreate within your own types
Within your own types you can also leverage the oncreate methods:
define product => type {
parent activerow
public oncreate(id::integer=0) => ..oncreate(::store.product,#id)
}
Or:
define product => type {
parent activerow
public oncreate(...keys) => ..oncreate(::store.product,#keys)
}
Or:
define product => type {
parent activerow
public oncreate(mpn::string) => ..oncreate(product_ds,::mpn = #mpn)
}
And finally a complete catch all:
define product => type {
parent activerow
public oncreate(...) => ..oncreate(:#rest)
}
####Configuration via Data Members & Methods
If you prefer you can configure you sub-types by providing either the database name or ds
definition via .database
and .ds
respectively. When using either approach you can also specify the table with .table
— by default a pluralised version of your type will be used for the table name.
define product => type {
parent activerow
public ds => ds(::store.product)
}
Or:
define product => type {
parent activerow
data
public database = 'store',
public table = 'products'
}
When .table
is blank activerow will use the types name suffixed with "s" as the table — you can change this with the following code:
define activerow_pluralise_tables => false
##Accessing row data — activerow
Data can be accessed in the same fashion as ds_row
with the added benefit of being able leverage your own methods defined in your types. This allows you to format the data in a particular way or create another accessor for the data.
Return the value of the specified column:
(column::tag)
-> find(column::tag)
-> find(column::string)
#activerow(::mycolumn)
#activerow->find('mycolumn')
When used in your own types you can create one to one methods like so:
public mycolumn => .find(::mycolumn)
Or you can use methods with different names like so:
public firstname => .find(::user_firstname)
public lastname => .find('user_lastname') // also valid
Bringing it all together:
public qty => .find(::item_qty)
public price => .find(::item_price)
public subtotal => .price * .qty
##Modifying row data — activerow
####(column::tag) = value, (column::string) = value Updates internal data — does not write to data source.
#activerow(::mycol) = 'Value'
#activerow('mycol') = 'Value'
####-> updatedata
-> updatedata(data::trait_foreachpair)
-> updatedata(p::pair,...)
Updates internal data only — does not write to data source.
#activerow->updatedata(map('price' = 9.95, 'qty' = 3))
####-> update
-> update(data::trait_foreachpair)
-> update(p::pair,...)
Updates internal data and writes to data source.
#activerow->update(::price = 9.95, ::qty = 3)
// Or
#activerow->update(
map(
'price' = 9.95,
'qty' = 3
)
)
####-> set
-> set(p::pair)
-> set(column::tag) = value
-> set(column::string) = value
Update internal data and writes specified value to the data source.
// These all have the same effect
#activerow->set(::mycol) = 'Value'
#activerow->set('mycol') = 'Value'
// Supplied as a pair
#activerow->set(::mycol = 'Value')
#activerow->set('mycol' = 'Value')
####-> create Creates new row in the data source and assigns the newly created row to the type.
####-> save Either updates or creates a row depending if it's new or not (based on keyvalue).
####-> delete Clears row data and deletes the row from the data source.
####-> revert Reverts unsaved changes.
####-> isnew Returns true if new.
####-> asnew
Returns copy of the activerow
with a null key value (considered new).
##Changing activerow behavior
You can change the default behaviour of the above by redefining them in your type. For example you may want to perform additional tasks on save or disable deleting by replacing it with an update.
define example => type {
parent activerow
// Extend default save method
public save => {
// Do something else
log(.type + ' saved by ' + current_user->name)
// Now actually save
..save
}
// Override default delete method
public delete => .update(::status = -1)
}