Skip to content

Active Row

Ke- edited this page Dec 2, 2013 · 34 revisions

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 is designed to be the 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.

The activerow type can be created with the following creators:

####-> oncreate(row::ds_row) ####-> oncreate(keyvalue,::database.table) ####-> oncreate(keyvalue,ds::ds)

Alternatively, the subtype should provide either the database name or ds definition via .database and .ds respectively. When using either approach you can also specify the table with .table

	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.

##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

####-> updatedata(data::trait_foreachpair), updatedata(p::pair,...) Update internal data only — does not write to data source.

#activerow->updatedata(map('price' = 9.95, 'qty' = 3))

####-> 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
    )
)

####-> (column::tag) = value, ->(column::string) = value Updates internal data and writes specified value to the data source.

#activerow(::mycol) = 'Value'
#activerow('mycol') = 'Value'

####-> set(column = value), set(column::tag) = value, set(column::string) = value Updates internal data and writes specified value to the data source.

// These all have the same effect
#activerow->set(::mycol) = 'Value'
#activerow->set(::mycol = 'Value')

#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.

Other activerow methods

####-> isnew Returns true if new.

####-> asnew Returns copy of type 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)
	}