diff --git a/src/mesh/Entity.as b/src/mesh/Entity.as index c5dc741..51de90b 100644 --- a/src/mesh/Entity.as +++ b/src/mesh/Entity.as @@ -1,26 +1,23 @@ package mesh { - import collections.ISet; - + import flash.errors.IllegalOperationError; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.utils.Proxy; - import flash.utils.flash_proxy; import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; import flash.utils.getQualifiedSuperclassName; import flash.utils.setTimeout; - import mesh.adaptors.ServiceAdaptor; - import mesh.associations.AssociationCollection; - import mesh.associations.AssociationProxy; - import mesh.associations.Relationship; + import mesh.associations.Association; + import mesh.associations.AssociationDefinition; + import mesh.associations.HasManyAssociation; + import mesh.associations.HasManyDefinition; + import mesh.associations.HasOneAssociation; + import mesh.associations.HasOneDefinition; import mesh.core.inflection.humanize; - import mesh.core.reflection.Property; - import mesh.core.reflection.className; - import mesh.core.reflection.clazz; - import mesh.core.reflection.reflect; + import mesh.core.reflection.Type; import mesh.validators.Errors; import mesh.validators.Validator; @@ -34,10 +31,12 @@ package mesh * * @author Dan Schultz */ - public dynamic class Entity extends Proxy implements IEventDispatcher, IPersistable + public class Entity extends Proxy implements IEventDispatcher, IPersistable { private var _dispatcher:EventDispatcher; private var _callbacks:Callbacks = new Callbacks(); + private var _associations:Object = {}; + private var _changes:Properties = new Properties(this); /** * Constructor. @@ -49,33 +48,51 @@ package mesh _dispatcher = new EventDispatcher(this); // add necessary callbacks for find - afterFind(function(entity:Entity):void - { - _properties.clear(); - }); - afterFind(function(entity:Entity):void - { - markNonLazyAssociationsAsLoaded(); - }); + afterFind(synced); + afterFind(markNonLazyAssociationsAsLoaded); // add necessary callbacks for save - afterSave(function(entity:Entity):void - { - _properties.clear(); - }); + beforeSave(validate); + afterSave(synced); // add necessary callback for destory - afterDestroy(function(entity:Entity):void - { - _isDestroyed = true; - }); + afterDestroy(destroyed); addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, handlePropertyChange); } - public function afterFind(block:Function):void + /** + * 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 + * a has-many relationship, a HasManyAssociation is returned. + * + * @param property The property of the relationship to get the proxy for. + * @return An association proxy. + */ + protected function association(property:String):* { - addCallback("afterFind", block); + if (!_associations.hasOwnProperty(property)) { + throw new ArgumentError("Undefined association on property '" + property + "'"); + } + return _associations[property]; + } + + protected function associate(property:String, definition:AssociationDefinition):Association + { + if (!_associations.hasOwnProperty(property)) { + _associations[property] = definition.createProxy(this); + } + return _associations[property]; + } + + protected function hasOne(clazz:Class, property:String, options:Object = null):HasOneAssociation + { + return associate(clazz, property, new HasOneDefinition(reflect.clazz, property, clazz, options)); + } + + protected function hasMany(clazz:Class, property:String, options:Object = null):HasManyAssociation + { + return associate(clazz, property, new HasManyDefinition(reflect.clazz, property, clazz, options)); } /** @@ -88,7 +105,7 @@ package mesh private function addCallback(method:String, block:Function):void { - _callbacks.addCallback(method, block, [this]); + _callbacks.addCallback(method, block, []); } /** @@ -106,34 +123,6 @@ package mesh return operation; } - /** - * @copy Callbacks#removeCallback() - */ - public function removeCallback(block:Function):void - { - _callbacks.removeCallback(block); - } - - /** - * 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 - * a has-many relationship, a HasManyAssociation is returned. - * - * @param property The property of the relationship to get the proxy for. - * @return An association proxy. - */ - public function association(property:String):AssociationProxy - { - if (!_associations.hasOwnProperty(property)) { - var relationship:Relationship = descriptor.getRelationshipForProperty(property); - if (relationship == null) { - throw new ArgumentError("Relationship not defined for '" + property + "'"); - } - _associations[property] = relationship.createProxy(this); - } - return _associations[property]; - } - /** * Checks if two entities are equal. By default, two entities are equal * when they are of the same type, and their ID's are the same. @@ -141,11 +130,9 @@ package mesh * @param entity The entity to check. * @return true if the entities are equal. */ - public function equals(entity:Entity):Boolean + public function equals(obj:Object):Boolean { - return entity != null && - (this === entity || (isPersisted && id === entity.id)) && - clazz(this) == clazz(entity); + return obj != null && (this === obj || (obj is Entity && isPersisted && id === obj.id)); } /** @@ -162,20 +149,43 @@ package mesh return operation; } - public function beforeDestroy(block:Function):void + protected function beforeDestroy(block:Function):void { addCallback("beforeDestroy", block); } - public function afterDestroy(block:Function):void + /** + * Adds a callback function that will be executed before a save operation. If this + * function returns false or throws an error, the save will halt. + * + * @param block The callback function. + */ + protected function beforeSave(block:Function):void + { + addCallback("beforeSave", block); + } + + protected function afterDestroy(block:Function):void { addCallback("afterDestroy", block) } + protected function afterFind(block:Function):void + { + addCallback("afterFind", block); + } + /** - * Called when the entity has been successfully destroyed from its backend service. + * Adds a callback function that will be executed after a save operation has finished. + * + * @param block The callback function. */ - protected function destroyed():void + protected function afterSave(block:Function):void + { + addCallback("afterSave", block); + } + + private function destroyed():void { _isDestroyed = true; } @@ -236,7 +246,7 @@ package mesh { // check if the property is ignored. if (!ignoredProperties.contains(property)) { - _properties.changed(property, oldValue, newValue); + _changes.changed(property, oldValue, newValue); } } @@ -245,7 +255,7 @@ package mesh */ public function revert():void { - _properties.revert(); + _changes.revert(); } /** @@ -276,8 +286,8 @@ package mesh batch.update(this); } - for each (var association:AssociationProxy in associations) { - if (association.relationship.autoSave) { + for each (var association:Association in associations) { + if (association.definition.autoSave) { batch.add(association); } } @@ -308,47 +318,15 @@ package mesh return operation; } - /** - * Adds a callback function that will be executed before a save operation. If this - * function returns false or throws an error, the save will halt. - * - * @param block The callback function. - */ - public function beforeSave(block:Function):void - { - addCallback("beforeSave", block); - } - - /** - * Adds a callback function that will be executed after a save operation has finished. - * - * @param block The callback function. - */ - public function afterSave(block:Function):void + private function synced():void { - addCallback("afterSave", block); - } - - /** - * Marks this entity as being persisted. - */ - public function persisted():void - { - _properties.clear(); - } - - /** - * Marks this entity as being loaded from its backend service. - */ - public function found():void - { - callback("afterFind"); + _changes.clear(); } private function markNonLazyAssociationsAsLoaded():void { - for each (var association:AssociationProxy in associations) { - if (!association.relationship.isLazy && !association.isLoaded) { + for each (var association:Association in associations) { + if (!association.definition.isLazy && !association.isLoaded) { association.loaded(); } } @@ -367,53 +345,7 @@ package mesh */ public function toString():String { - return humanize(className(this)); - } - - public function toJSON(options:Object = null):Object - { - return null; - } - - public function toXML(options:Object = null):XML - { - return null; - } - - public function toVO(options:Object = null):Object - { - var vo:Object = new descriptor.voType(); - for each (var property:String in properties) { - if (options == null || !options.hasOwnProperty("including") || options.including.indexOf(property) != -1) { - if (options == null || (!options.hasOwnProperty("excluding") || options.excluding.indexOf(property) == -1)) { - var value:Object = descriptor.getRelationshipForProperty(property) != null ? association(property) : this[property]; - if (value != null && value.hasOwnProperty("toVO")) { - // need to pass through the options provided for this property. - var propertyOptions:Object = {}; - - if (value is AssociationCollection) { - propertyOptions.type = reflect(vo).property(property).type.clazz; - } - - value = value.toVO(propertyOptions); - } - vo[property] = value; - } - } - } - return vo; - } - - public function fromVO(vo:Object, options:Object = null):void - { - for each (var property:Property in reflect(vo).properties) { - var value:Object = this[property]; - if (value != null && value.hasOwnProperty("fromVO")) { - value.fromVO(vo[property]); - } else { - this[property] = vo[property]; - } - } + return humanize(reflect.className); } /** @@ -444,20 +376,9 @@ package mesh * @param property The property to retrieve. * @return The property's previous value. */ - public function was(property:String):* - { - return _properties.oldValueOf(property); - } - - /** - * Returns the mapped instance of the service adaptor for the given entity. - * - * @param entity The entity to get the service adaptor for. - * @return A service adaptor. - */ - public static function adaptorFor(entity:Object):ServiceAdaptor + public function whatWas(property:String):* { - return EntityDescription.describe(entity).adaptor; + return _changes.oldValueOf(property); } /** @@ -476,7 +397,7 @@ package mesh */ private function validate():Array { - _errors = null; + errors.clear(); var clazz:Class = getDefinitionByName(getQualifiedClassName(this)) as Class; while (clazz != Entity) { @@ -493,37 +414,9 @@ package mesh return errors.toArray(); } - /** - * The adaptor defined for this entity. - */ - public function get adaptor():ServiceAdaptor - { - return descriptor.adaptor; - } - - /** - * The set of associations that belong to this entity. - */ - public function get associations():Array + public function adaptor():Class { - var result:Array = []; - for each (var relationship:Relationship in descriptor.relationships) { - result.push(association(relationship.property)); - } - return result; - } - - private var _descriptor:EntityDescription; - /** - * The description that contains the aggregates, relationships, validators and service - * adaptor for this entity. - */ - public function get descriptor():EntityDescription - { - if (_descriptor == null) { - _descriptor = EntityDescription.describe(this); - } - return _descriptor; + throw new IllegalOperationError(reflect.className + ".adaptor is not implemented.") } private var _errors:Errors; @@ -594,7 +487,7 @@ package mesh */ public function get hasPropertyChanges():Boolean { - return _properties.hasChanges; + return _changes.hasChanges; } /** @@ -602,8 +495,8 @@ package mesh */ public function get hasDirtyAssociations():Boolean { - for each (var association:AssociationProxy in associations) { - if (association.relationship.autoSave && association.isDirty) { + for each (var association:Association in _associations) { + if (association.definition.autoSave && association.isDirty) { return true; } } @@ -638,134 +531,17 @@ package mesh return _isMarkedForRemoval; } + private var _reflect:Type; /** - * A set of properties that are accessible on this entity. Properties include any that - * are defined on the entity and its sub-classes, and any properties defined within - * metadata, such as ComposedOf or HasOne. - */ - public function get properties():ISet - { - return descriptor.properties; - } - - private function get ignoredProperties():ISet - { - return descriptor.ignoredProperties; - } - - /** - * @private - */ - override flash_proxy function callProperty(name:*, ...parameters):* - { - throw new Error("Method '" + name + "' does not exist on " + className(this) + "."); - } - - private var _properties:Properties = new Properties(this); - private var _associations:Properties = new Properties(this); - /** - * @private - */ - override flash_proxy function getProperty(name:*):* - { - // check if the caller wants the association - if (descriptor.getRelationshipForProperty(name) != null) { - return association(name); - } - - // check if the caller wants the association proxy. - if (name.toString().indexOf("Association") > 0) { - return association(name.toString().replace("Association", "")); - } - - if (_properties.hasOwnProperty(name)) { - return _properties[name]; - } - - var aggregate:Aggregate = descriptor.getAggregateForProperty(name); - if (aggregate != null && aggregate.property != name.toString()) { - return aggregate.getValue(this, name); - } - - if (name.toString().lastIndexOf("Was") == name.toString().length-3) { - var property:String = name.toString().substr(0, name.toString().length-3); - - aggregate = descriptor.getAggregateForProperty(property); - if (aggregate != null) { - var aggregateValue:Object = _properties.oldValueOf(aggregate.property); - if (aggregateValue != null) { - return aggregateValue[aggregate.getMappedProperty(property)]; - } - } - return was(property); - } - - return undefined; - } - - /** - * @private - */ - override flash_proxy function hasProperty(name:*):Boolean - { - return flash_proxy::getProperty(name) !== undefined; - } - - /** - * @private + * A reflection that contains the properties, methods and metadata defined on this + * entity. */ - override flash_proxy function setProperty(name:*, value:*):void + public function get reflect():Type { - if (!properties.contains(name.toString())) { - throw new ArgumentError(name + " not defined on " + className(this)); - } - - if (descriptor.getRelationshipForProperty(name) != null) { - association(name).target = value is AssociationProxy ? value.target : value; - return; - } - - var oldValue:* = _properties[name]; - _properties[name] = value; - - var aggregate:Aggregate = descriptor.getAggregateForProperty(name); - if (aggregate != null && aggregate.property != name.toString()) { - aggregate.setValue(this, name, value); - return; - } - if (aggregate != null && aggregate.isBindable && aggregate.property == name.toString()) { - dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, name.toString(), oldValue, value)); + if (_reflect == null) { + _reflect = Type.reflect(this); } - } - - /** - * @private - */ - override flash_proxy function nextName(index:int):String - { - return _iteratingProperties[index-1]; - } - - private var _iteratingProperties:Array; - private var _len:int; - /** - * @private - */ - override flash_proxy function nextNameIndex(index:int):int - { - if (index == 0) { - _iteratingProperties = properties.toArray(); - _len = _iteratingProperties.length; - } - return index < _len ? index+1 : 0; - } - - /** - * @private - */ - override flash_proxy function nextValue(index:int):* - { - return this[_iteratingProperties[index-1]]; + return _reflect; } /** diff --git a/src/mesh/EntityDescription.as b/src/mesh/EntityDescription.as index 4eb6d77..0d9cfc8 100644 --- a/src/mesh/EntityDescription.as +++ b/src/mesh/EntityDescription.as @@ -13,9 +13,9 @@ package mesh import mesh.adaptors.ServiceAdaptor; import mesh.associations.BelongsToRelationship; - import mesh.associations.HasManyRelationship; - import mesh.associations.HasOneRelationship; - import mesh.associations.Relationship; + import mesh.associations.HasManyDefinition; + import mesh.associations.HasOneDefinition; + import mesh.associations.AssociationDefinition; import mesh.core.reflection.clazz; import mesh.core.reflection.newInstance; @@ -24,8 +24,8 @@ package mesh public class EntityDescription { private static const RELATIONSHIPS:Object = { - HasMany: HasManyRelationship, - HasOne: HasOneRelationship, + HasMany: HasManyDefinition, + HasOne: HasOneDefinition, BelongsTo: BelongsToRelationship }; @@ -85,7 +85,7 @@ package mesh public function addRelationships(...relationships):void { - for each (var relationship:Relationship in relationships) { + for each (var relationship:AssociationDefinition in relationships) { _relationships.add(relationship); _propertyToRelationship.put(relationship.property, relationship); } @@ -101,7 +101,7 @@ package mesh return _propertyToAggregate.grab(property); } - public function getRelationshipForProperty(property:String):Relationship + public function getRelationshipForProperty(property:String):AssociationDefinition { return _propertyToRelationship.grab(property); } @@ -315,7 +315,7 @@ package mesh _properties.addAll(aggregate.properties); } - for each (var relationship:Relationship in relationships) { + for each (var relationship:AssociationDefinition in relationships) { _properties.addAll(relationship.properties); } diff --git a/src/mesh/SaveBatch.as b/src/mesh/SaveBatch.as index de626b9..747a079 100644 --- a/src/mesh/SaveBatch.as +++ b/src/mesh/SaveBatch.as @@ -109,7 +109,7 @@ import collections.HashSet; import mesh.Entity; import mesh.EntityDescription; import mesh.associations.BelongsToRelationship; -import mesh.associations.Relationship; +import mesh.associations.AssociationDefinition; import mesh.core.string.capitalize; import operations.EmptyOperation; @@ -134,7 +134,7 @@ class PersistenceCache private function countLongestParentPath(description:EntityDescription):int { var count:int = 0; - for each (var relationship:Relationship in description.relationships) { + for each (var relationship:AssociationDefinition in description.relationships) { if (relationship is BelongsToRelationship) { count = Math.max(count, countLongestParentPath(EntityDescription.describe(relationship.target)) + 1); } diff --git a/src/mesh/associations/AssociationProxy.as b/src/mesh/associations/Association.as similarity index 66% rename from src/mesh/associations/AssociationProxy.as rename to src/mesh/associations/Association.as index 54a8e3e..0d48f9f 100644 --- a/src/mesh/associations/AssociationProxy.as +++ b/src/mesh/associations/Association.as @@ -1,13 +1,10 @@ package mesh.associations { - import collections.HashMap; - import flash.errors.IllegalOperationError; import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.utils.Proxy; - import flash.utils.describeType; import flash.utils.flash_proxy; import flash.utils.setTimeout; @@ -17,7 +14,6 @@ package mesh.associations import mesh.Mesh; import mesh.SaveBatch; import mesh.core.reflection.className; - import mesh.core.reflection.clazz; import mx.events.PropertyChangeEvent; @@ -27,13 +23,13 @@ package mesh.associations import operations.ResultOperationEvent; /** - * An association proxy is a class that contains the references to the objects in - * a relationship, where the owner represents the object hosting the - * association, and the target is the actual associated object. + * An association class is a proxy object that contains the references to the objects in + * a relationship, where the owner represents the object hosting the association, + * and the target is the actual associated object. * * @author Dan Schultz */ - public dynamic class AssociationProxy extends Proxy implements IEventDispatcher, IPersistable + public dynamic class Association extends Proxy implements IEventDispatcher, IPersistable { private var _dispatcher:EventDispatcher; private var _callbacks:Callbacks = new Callbacks(); @@ -44,36 +40,28 @@ package mesh.associations * @param owner The parent that owns the relationship. * @param relationship The relationship being represented by the proxy. */ - public function AssociationProxy(owner:Entity, relationship:Relationship) + public function Association(owner:Entity, definition:AssociationDefinition) { super(); _dispatcher = new EventDispatcher(this); _owner = owner; - _relationship = relationship; - - beforeLoad(function(proxy:AssociationProxy):void - { - setBindableProperty("isLoading", function():Boolean { return isLoading; }, function():void { _isLoading = true; }); - }); + _definition = definition; - afterLoad(function(proxy:AssociationProxy):void - { - setBindableProperty("isLoaded", function():Boolean { return isLoaded; }, function():void { _isLoaded = true; }); - setBindableProperty("isLoading", function():Boolean { return isLoading; }, function():void { _isLoading = false; }); - }); + beforeLoad(loading); + afterLoad(loaded); } private function addCallback(method:String, block:Function):void { - _callbacks.addCallback(method, block, [this]); + _callbacks.addCallback(method, block); } - public function beforeLoad(block:Function):void + protected function beforeLoad(block:Function):void { addCallback("beforeLoad", block); } - public function afterLoad(block:Function):void + protected function afterLoad(block:Function):void { addCallback("afterLoad", block); } @@ -83,32 +71,6 @@ package mesh.associations _callbacks.callback(method); } - public function fromVO(vo:Object, options:Object = null):void - { - - } - - private static const VO_TO_ENTITY:HashMap = new HashMap(); - protected function createEntityFromVOMapping(vo:Object, options:Object = null):Entity - { - var voType:Class = clazz(vo); - if (!VO_TO_ENTITY.containsKey(voType)) { - for each (var metadataXML:XML in describeType(vo)..metadata.(@name == "Entity")) { - VO_TO_ENTITY.put(voType, metadataXML.parent().@type); - break; - } - } - - var entityType:Class = VO_TO_ENTITY.grab(voType); - if (entityType == null) { - throw new IllegalOperationError("Entity mapping not found for " + className(vo)); - } - - var entity:Entity = new entityType(); - entity.fromVO(vo, options); - return entity; - } - /** * Executes an operation that will load the target for this association. * @@ -116,18 +78,12 @@ package mesh.associations */ final public function load():Operation { - var operation:Operation = isLoaded ? new EmptyOperation() : createLoad(); - setTimeout(operation.execute, 50); + var operation:Operation = (isLoaded || isLoading) ? new EmptyOperation() : createLoad(); + setTimeout(operation.execute, Mesh.DELAY); return operation; } - /** - * Generates an unexecuted operation that will be used to load the target of the - * association. - * - * @return An unexecuted operation. - */ - public function createLoad():Operation + private function createLoad():Operation { var operation:Operation = createLoadOperation(); operation.addEventListener(ResultOperationEvent.RESULT, function(event:ResultOperationEvent):void @@ -141,20 +97,22 @@ package mesh.associations return operation; } - /** - * Called by createLoad() to generate a query operation that is specific for this - * association. This method must be overridden and implemented by each association. - * - * @return An unexecuted operation. - */ - protected function createLoadOperation():Operation + private function loading():void { - throw new IllegalOperationError(className(this) + ".createLoadOperation() is not implemented."); + if (!_isLoading) { + _isLoading = true; + dispatchEvent( PropertyChangeEvent.createUpdateEvent(this, "isLoading", false, true) ); + } } - public function loaded():void + private function loaded():void { - callback("afterLoad"); + if (!_isLoaded) { + _isLoaded = true; + _isLoading = false; + dispatchEvent( PropertyChangeEvent.createUpdateEvent(this, "isLoading", true, false) ); + dispatchEvent( PropertyChangeEvent.createUpdateEvent(this, "isLoaded", false, true) ); + } } /** @@ -165,8 +123,8 @@ package mesh.associations */ protected function populateBelongsToAssociation(entity:Entity):void { - for each (var association:AssociationProxy in entity.associations) { - if (association is BelongsToAssociation && relationship.target == association.relationship.owner) { + for each (var association:Association in entity.associations) { + if (association is BelongsToAssociation && definition.target == association.definition.owner) { association.target = owner; break; } @@ -236,13 +194,13 @@ package mesh.associations return _isLoading; } - private var _relationship:Relationship; + private var _definition:AssociationDefinition; /** * The relationship model that this association represents. */ - public function get relationship():Relationship + public function get definition():AssociationDefinition { - return _relationship; + return _definition; } private var _owner:Entity; diff --git a/src/mesh/associations/AssociationCollection.as b/src/mesh/associations/AssociationCollection.as index bcb4d63..c9ece80 100644 --- a/src/mesh/associations/AssociationCollection.as +++ b/src/mesh/associations/AssociationCollection.as @@ -24,7 +24,7 @@ package mesh.associations use namespace flash_proxy; - public dynamic class AssociationCollection extends AssociationProxy implements IList + public dynamic class AssociationCollection extends Association implements IList { private var _originalEntities:ArraySequence; private var _mirroredEntities:ArraySequence; @@ -33,7 +33,7 @@ package mesh.associations /** * @copy AssociationProxy#AssociationProxy() */ - public function AssociationCollection(source:Entity, relationship:Relationship) + public function AssociationCollection(source:Entity, relationship:AssociationDefinition) { super(source, relationship); target = []; diff --git a/src/mesh/associations/Relationship.as b/src/mesh/associations/AssociationDefinition.as similarity index 91% rename from src/mesh/associations/Relationship.as rename to src/mesh/associations/AssociationDefinition.as index 85f4cf7..6ceadcc 100644 --- a/src/mesh/associations/Relationship.as +++ b/src/mesh/associations/AssociationDefinition.as @@ -22,7 +22,7 @@ package mesh.associations * * @author Dan Schultz */ - public dynamic class Relationship extends Proxy + public dynamic class AssociationDefinition extends Proxy { /** * Constructor. @@ -32,7 +32,7 @@ package mesh.associations * @param target The destination of the association. * @param options A set of options defined for this relationship. */ - public function Relationship(owner:Class, property:String, target:Class, options:Object) + public function AssociationDefinition(owner:Class, property:String, target:Class, options:Object) { if (property == null || property.length == 0) { throw new ArgumentError("Missing property for '" + humanize(className(this)).toLowerCase() + "' on " + className(owner)); @@ -55,8 +55,8 @@ package mesh.associations */ public function createProxy(entity:Entity):* { - var associationClassName:String = getQualifiedClassName(this).replace("Relationship", "Association"); - var proxy:AssociationProxy = newInstance(getDefinitionByName(associationClassName) as Class, entity, this); + var associationClassName:String = getQualifiedClassName(this).replace("Definition", "Association"); + var proxy:Association = newInstance(getDefinitionByName(associationClassName) as Class, entity, this); if (proxy == null) { throw new IllegalOperationError("Could not find proxy for " + className(this)); } @@ -69,7 +69,7 @@ package mesh.associations * @param relationship The relationship to check with. * @return true if the two are equal. */ - public function equals(relationship:Relationship):Boolean + public function equals(relationship:AssociationDefinition):Boolean { return relationship != null && owner == relationship.owner && @@ -175,7 +175,7 @@ package mesh.associations { // supports calls like: relationship.isHasOne, or relationship.isHasMany. if (name.toString().indexOf("is") == 0) { - return camelize(name.toString().replace("is", ""), false) == className(this).replace(className(Relationship), ""); + return camelize(name.toString().replace("is", ""), false) == className(this).replace(className(AssociationDefinition), ""); } // supports calls like: relationship.hasLazy diff --git a/src/mesh/associations/BelongsToAssociation.as b/src/mesh/associations/BelongsToAssociation.as index 74e018c..3ff65c8 100644 --- a/src/mesh/associations/BelongsToAssociation.as +++ b/src/mesh/associations/BelongsToAssociation.as @@ -11,7 +11,7 @@ package mesh.associations /** * @copy AssociationProxy#AssociationProxy() */ - public function BelongsToAssociation(owner:Entity, relationship:Relationship) + public function BelongsToAssociation(owner:Entity, relationship:AssociationDefinition) { super(owner, relationship); } @@ -21,7 +21,7 @@ package mesh.associations */ override protected function createLoadOperation():Operation { - var operation:Operation = Query.entity(relationship.target).find(owner[BelongsToRelationship( relationship ).foreignKey]); + var operation:Operation = Query.entity(definition.target).find(owner[BelongsToRelationship( definition ).foreignKey]); operation.addEventListener(ResultOperationEvent.RESULT, function(event:ResultOperationEvent):void { event.data = event.data[0]; diff --git a/src/mesh/associations/BelongsToRelationship.as b/src/mesh/associations/BelongsToRelationship.as index 7336319..151a78f 100644 --- a/src/mesh/associations/BelongsToRelationship.as +++ b/src/mesh/associations/BelongsToRelationship.as @@ -7,7 +7,7 @@ package mesh.associations * * @author Dan Schultz */ - public class BelongsToRelationship extends HasOneRelationship + public class BelongsToRelationship extends HasOneDefinition { /** * @copy Relationship#Relationship() diff --git a/src/mesh/associations/HasAssociation.as b/src/mesh/associations/HasAssociation.as index bbf6874..4902cf0 100644 --- a/src/mesh/associations/HasAssociation.as +++ b/src/mesh/associations/HasAssociation.as @@ -2,12 +2,12 @@ package mesh.associations { import mesh.Entity; - public class HasAssociation extends AssociationProxy + public class HasAssociation extends Association { /** * @copy AssociationProxy#AssociationProxy() */ - public function HasAssociation(owner:Entity, relationship:Relationship) + public function HasAssociation(owner:Entity, relationship:AssociationDefinition) { super(owner, relationship); diff --git a/src/mesh/associations/HasManyAssociation.as b/src/mesh/associations/HasManyAssociation.as index 9b69c89..eed1e5a 100644 --- a/src/mesh/associations/HasManyAssociation.as +++ b/src/mesh/associations/HasManyAssociation.as @@ -12,7 +12,7 @@ package mesh.associations /** * @copy AssociationCollection#AssociationCollection() */ - public function HasManyAssociation(source:Entity, relationship:Relationship) + public function HasManyAssociation(source:Entity, relationship:AssociationDefinition) { super(source, relationship); } @@ -23,9 +23,9 @@ package mesh.associations override protected function createLoadOperation():Operation { var options:Object = {}; - options[camelize(className(relationship.owner), false)] = owner; + options[camelize(className(definition.owner), false)] = owner; - return Query.entity(relationship.target).where(options); + return Query.entity(definition.target).where(options); } /** diff --git a/src/mesh/associations/HasManyRelationship.as b/src/mesh/associations/HasManyDefinition.as similarity index 83% rename from src/mesh/associations/HasManyRelationship.as rename to src/mesh/associations/HasManyDefinition.as index 6a29c91..62a19cc 100644 --- a/src/mesh/associations/HasManyRelationship.as +++ b/src/mesh/associations/HasManyDefinition.as @@ -12,12 +12,12 @@ package mesh.associations * * @author Dan Schultz */ - public class HasManyRelationship extends Relationship + public class HasManyDefinition extends AssociationDefinition { /** * @copy Relationship#Relationship() */ - public function HasManyRelationship(owner:Class, property:String, target:Class, options:Object) + public function HasManyDefinition(owner:Class, property:String, target:Class, options:Object) { if (property == null || property.length == 0) { property = camelize(pluralize(className(target)), false); diff --git a/src/mesh/associations/HasOneAssociation.as b/src/mesh/associations/HasOneAssociation.as index 30edeb8..06902fb 100644 --- a/src/mesh/associations/HasOneAssociation.as +++ b/src/mesh/associations/HasOneAssociation.as @@ -13,7 +13,7 @@ package mesh.associations /** * @copy HasAssociation#HasAssociation() */ - public function HasOneAssociation(owner:Entity, relationship:Relationship) + public function HasOneAssociation(owner:Entity, relationship:AssociationDefinition) { super(owner, relationship); } @@ -24,9 +24,9 @@ package mesh.associations override protected function createLoadOperation():Operation { var options:Object = {}; - options[camelize(className(relationship.owner), false)] = owner; + options[camelize(className(definition.owner), false)] = owner; - var operation:Operation = Query.entity(relationship.target).where(options); + var operation:Operation = Query.entity(definition.target).where(options); operation.addEventListener(ResultOperationEvent.RESULT, function(event:ResultOperationEvent):void { event.data = event.data[0]; diff --git a/src/mesh/associations/HasOneRelationship.as b/src/mesh/associations/HasOneDefinition.as similarity index 87% rename from src/mesh/associations/HasOneRelationship.as rename to src/mesh/associations/HasOneDefinition.as index 8175f22..8d56826 100644 --- a/src/mesh/associations/HasOneRelationship.as +++ b/src/mesh/associations/HasOneDefinition.as @@ -11,12 +11,12 @@ package mesh.associations * * @author Dan Schultz */ - public class HasOneRelationship extends Relationship + public class HasOneDefinition extends AssociationDefinition { /** * @copy Relationship#Relationship() */ - public function HasOneRelationship(owner:Class, property:String, target:Class, options:Object) + public function HasOneDefinition(owner:Class, property:String, target:Class, options:Object) { if (property == null || property.length == 0) { property = camelize(className(target), false); diff --git a/tests/mesh/RelationshipTests.as b/tests/mesh/RelationshipTests.as index d75ceb3..ccb77b1 100644 --- a/tests/mesh/RelationshipTests.as +++ b/tests/mesh/RelationshipTests.as @@ -1,7 +1,7 @@ package mesh { - import mesh.associations.HasManyRelationship; - import mesh.associations.HasOneRelationship; + import mesh.associations.HasManyDefinition; + import mesh.associations.HasOneDefinition; import mesh.models.Aircraft; import mesh.models.Airplane; import mesh.models.Customer; @@ -25,21 +25,21 @@ package mesh public function testRelationshipMetadata():void { var relationships:Array = new Customer().descriptor.relationships.toArray(); - assertThat(relationships, hasItem(allOf(instanceOf(HasManyRelationship), hasProperty("property", equalTo("orders"))))); + assertThat(relationships, hasItem(allOf(instanceOf(HasManyDefinition), hasProperty("property", equalTo("orders"))))); } [Test] public function testRelationshipMetadataSetsPropertyAsPluralizedType():void { var relationships:Array = new Customer().descriptor.relationships.toArray(); - assertThat(relationships, hasItem(allOf(instanceOf(HasManyRelationship), hasProperty("property", equalTo("cars"))))); + assertThat(relationships, hasItem(allOf(instanceOf(HasManyDefinition), hasProperty("property", equalTo("cars"))))); } [Test] public function testRelationshipMetadataOnGetterSetsPropertyAsGetter():void { var relationships:Array = new Customer().descriptor.relationships.toArray(); - assertThat(relationships, hasItem(allOf(instanceOf(HasOneRelationship), hasProperty("property", equalTo("account"))))); + assertThat(relationships, hasItem(allOf(instanceOf(HasOneDefinition), hasProperty("property", equalTo("account"))))); } [Test]