Skip to content

Commit

Permalink
adding helpers for aggregating properties into value objects.
Browse files Browse the repository at this point in the history
  • Loading branch information
danschultz committed Apr 20, 2011
1 parent 4a32f33 commit 443e76e
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 158 deletions.
158 changes: 0 additions & 158 deletions src/mesh/model/Aggregate.as

This file was deleted.

131 changes: 131 additions & 0 deletions src/mesh/model/Aggregates.as
@@ -0,0 +1,131 @@
package mesh.model
{
import flash.errors.IllegalOperationError;

import mesh.core.reflection.Type;

public class Aggregates
{
private var _host:Object;
private var _propertyToAggregate:Object = {};

public function Aggregates(host:Object)
{
_host = host;
}

public function add(property:String, type:Class, mappings:Array):void
{
if (_propertyToAggregate.hasOwnProperty(property)) {
throw new IllegalOperationError(Type.reflect(_host).name + "." + property + " is already mapped to an aggregate.");
}

var aggregate:Aggregate = new Aggregate(_host, property, type, mappings);
_propertyToAggregate[property] = aggregate;

for (var key:String in aggregate.mappings) {
_propertyToAggregate[key] = aggregate;
}
}

public function changed(property:String):void
{
if (_propertyToAggregate.hasOwnProperty(property)) {
_propertyToAggregate[property].changed(property);
}
}
}
}

import mesh.core.reflection.newInstance;

class Aggregate
{
/**
* Constructor.
*
* @param entity The host entity.
* @param property The property on the entity that the aggregate is mapped to.
* @param type The aggregate type class.
* @param mapping
*/
public function Aggregate(host:Object, property:String, type:Class, mappings:Array)
{
_host = host;
_property = property;
_type = type;

for each (var mapping:String in mappings) {
var keyValue:Array = mapping.split(":");

if (keyValue.length == 1) {
keyValue.push(keyValue[0]);
}

_mapSequence.push(keyValue[0]);
_mappings[keyValue[0]] = keyValue[1];
}
}

private var _changing:Boolean;
public function changed(property:String):void
{
if (!_changing) {
if (property == this.property) {
updateProperties();
} else {
updateAggregate()
}
}
}

private function updateAggregate():void
{
var args:Array = [];
for (var key:String in _mapSequence) {
args.push(mappings[key]);
}
_host[property] = newInstance.apply(null, [type].concat(args));
}

private function updateProperties():void
{
for (var key:String in mappings) {
_host[mappings[key]] = host[property][key];
}
}

private var _host:Object;
/**
* The host the aggregate.
*/
public function get host():Object
{
return _host;
}

private var _mapSequence:Array = [];
private var _mappings:Object = {};
public function get mappings():Object
{
return _mappings;
}

private var _property:String;
/**
* The property on the entity that the aggregate is mapped to.
*/
public function get property():String
{
return _property;
}

private var _type:Class;
/**
* The aggregate class.
*/
public function get type():Class
{
return _type;
}
}
7 changes: 7 additions & 0 deletions src/mesh/model/Entity.as
Expand Up @@ -35,6 +35,7 @@ package mesh.model
private var _callbacks:Callbacks = new Callbacks();
private var _observers:Callbacks = new Callbacks();
private var _associations:Object = {};
private var _aggregates:Aggregates = new Aggregates(this);
private var _changes:Changes = new Changes(this);

/**
Expand Down Expand Up @@ -79,6 +80,11 @@ package mesh.model
_observers.removeCallback(method, block);
}

protected function aggregate(property:String, type:Class, mappings:Array):void
{
_aggregates.add(property, type, mappings);
}

/**
* Returns an association proxy for the given the given property. The proxy that is
* returned is determined by the relationship type. For instance, if the property is
Expand Down Expand Up @@ -256,6 +262,7 @@ package mesh.model
protected function propertyChanged(property:String, oldValue:Object, newValue:Object):void
{
_changes.changed(property, oldValue, newValue);
_aggregates.changed(property);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions tests/mesh/Customer.as
Expand Up @@ -23,6 +23,8 @@ package mesh
public function Customer(properties:Object = null)
{
super(properties);

aggregate("address", Address, ["street:street", "city:city"]);
}

override public function translateTo():*
Expand Down
17 changes: 17 additions & 0 deletions tests/mesh/model/AggregateTestMockEntity.as
@@ -0,0 +1,17 @@
package mesh.model
{
import mesh.Name;

public class AggregateTestMockEntity extends Entity
{
[Bindable] public var name:Name;
[Bindable] public var firstName:String;
[Bindable] public var lastName:String;

public function AggregateTestMockEntity(values:Object=null)
{
super(values);
aggregate("name", Name, ["firstName", "lastName"]);
}
}
}
35 changes: 35 additions & 0 deletions tests/mesh/model/AggregateTests.as
@@ -0,0 +1,35 @@
package mesh.model
{
import mesh.Name;

import org.flexunit.assertThat;
import org.hamcrest.object.equalTo;

public class AggregateTests
{
private var _entity:AggregateTestMockEntity;

[Before]
public function setup():void
{
_entity = new AggregateTestMockEntity();
}

[Test]
public function testPropertyChangeUpdatesAggregate():void
{
_entity.firstName = "Thom";
_entity.lastName = "Yorke";
assertThat(_entity.name.firstName, equalTo(_entity.firstName));
assertThat(_entity.name.lastName, equalTo(_entity.lastName));
}

[Test]
public function testAggregateChangeUpdatesProperties():void
{
_entity.name = new Name("Thom", "Yorke");
assertThat(_entity.firstName, equalTo(_entity.name.firstName));
assertThat(_entity.lastName, equalTo(_entity.name.lastName));
}
}
}

0 comments on commit 443e76e

Please sign in to comment.