From 1a5539e8ed22b613021c1b3937fd2db9826655f9 Mon Sep 17 00:00:00 2001 From: Dan Schultz Date: Wed, 24 Aug 2011 16:24:51 -0700 Subject: [PATCH] Add tests and fix issues with finding entities in the store --- src/mesh/core/object/copy.as | 2 + src/mesh/model/source/FixtureSource.as | 19 ++++++ src/mesh/model/source/MultiSource.as | 11 ++++ src/mesh/model/source/Source.as | 2 +- src/mesh/model/store/Queries.as | 13 ++-- src/mesh/model/store/Query.as | 10 ++- src/mesh/model/store/ResultList.as | 2 +- tests/mesh/Address.as | 24 +++++++- tests/mesh/Customer.as | 16 +++-- tests/mesh/Name.as | 22 ++++++- tests/mesh/Person.as | 16 +++++ .../model/serialization/SerializerTests.as | 6 +- tests/mesh/model/store/FindTests.as | 61 +++++++++++++++++++ 13 files changed, 183 insertions(+), 21 deletions(-) create mode 100644 tests/mesh/model/store/FindTests.as diff --git a/src/mesh/core/object/copy.as b/src/mesh/core/object/copy.as index db2742a..992a5f6 100644 --- a/src/mesh/core/object/copy.as +++ b/src/mesh/core/object/copy.as @@ -42,6 +42,8 @@ package mesh.core.object } } catch (e:ReferenceError) { + } catch (e:TypeError) { + } } } diff --git a/src/mesh/model/source/FixtureSource.as b/src/mesh/model/source/FixtureSource.as index c9b03f2..05e55ba 100644 --- a/src/mesh/model/source/FixtureSource.as +++ b/src/mesh/model/source/FixtureSource.as @@ -4,10 +4,13 @@ package mesh.model.source import flash.utils.setTimeout; import mesh.core.object.merge; + import mesh.core.reflection.newInstance; import mesh.model.Entity; import mesh.model.store.Commit; + import mesh.model.store.Query; import mesh.model.store.Store; + import mx.collections.ArrayList; import mx.rpc.Fault; public class FixtureSource extends Source @@ -55,6 +58,22 @@ package mesh.model.source }); } + /** + * @inheritDoc + */ + override public function fetch(store:Store, query:Query):void + { + if (query.entityType == _entityType) { + var entities:Array = []; + for each (var hash:Object in _fixtures) { + var entity:Entity = newInstance(_entityType); + entity.fromObject(hash); + entities.push(entity); + } + store.query.loaded(query, new ArrayList(entities)); + } + } + /** * @inheritDoc */ diff --git a/src/mesh/model/source/MultiSource.as b/src/mesh/model/source/MultiSource.as index 0c2c987..acb505a 100644 --- a/src/mesh/model/source/MultiSource.as +++ b/src/mesh/model/source/MultiSource.as @@ -6,6 +6,7 @@ package mesh.model.source import mesh.core.reflection.reflect; import mesh.model.Entity; import mesh.model.store.Commit; + import mesh.model.store.Query; import mesh.model.store.Store; /** @@ -78,6 +79,16 @@ package mesh.model.source invokeEach(commit, "destroyEach", entities); } + /** + * @inheritDoc + */ + override public function fetch(store:Store, query:Query):void + { + for each (var source:Source in _mapping) { + source.fetch(store, query); + } + } + /** * @inheritDoc */ diff --git a/src/mesh/model/source/Source.as b/src/mesh/model/source/Source.as index dce95d6..7cbc5a0 100644 --- a/src/mesh/model/source/Source.as +++ b/src/mesh/model/source/Source.as @@ -49,7 +49,7 @@ package mesh.model.source } } - public function fetch(query:Query):void + public function fetch(store:Store, query:Query):void { throw new IllegalOperationError("EntitySource.fetch() is not implemented."); } diff --git a/src/mesh/model/store/Queries.as b/src/mesh/model/store/Queries.as index 79324fa..2a1ac71 100644 --- a/src/mesh/model/store/Queries.as +++ b/src/mesh/model/store/Queries.as @@ -2,8 +2,6 @@ package mesh.model.store { import flash.utils.Dictionary; - import mesh.model.source.Source; - import mx.collections.IList; /** @@ -48,7 +46,12 @@ package mesh.model.store if (!contains(query)) { throw new ArgumentError("Query '" + query + "' not found in cache."); } - results(query).loaded(entities); + + if (entities != null) _store.add.apply(null, entities.toArray()); + + if (query is RemoteQuery) { + results(query).loaded(entities); + } } /** @@ -61,7 +64,9 @@ package mesh.model.store internal function results(query:Query):ResultList { if (!contains(query)) { - _cache[query] = new ResultList(query, _store).refresh(); + var result:ResultList = new ResultList(query, _store); + _cache[query] = result; + result.refresh(); } return _cache[query]; } diff --git a/src/mesh/model/store/Query.as b/src/mesh/model/store/Query.as index e78ef14..ea47273 100644 --- a/src/mesh/model/store/Query.as +++ b/src/mesh/model/store/Query.as @@ -50,7 +50,15 @@ package mesh.model.store */ public function contains(entity:Entity):Boolean { - return _condition != null ? _condition(entity) : false; + if (_condition != null) { + return _condition(entity); + } + + if (entityType != null) { + return entity.reflect.isA(entityType); + } + + return false; } /** diff --git a/src/mesh/model/store/ResultList.as b/src/mesh/model/store/ResultList.as index 8f3cff9..bc2792a 100644 --- a/src/mesh/model/store/ResultList.as +++ b/src/mesh/model/store/ResultList.as @@ -79,7 +79,7 @@ package mesh.model.store */ public function refresh():ResultList { - _store.dataSource.fetch(_query); + _store.dataSource.fetch(_store, _query); if (_query is LocalQuery) { createList(_store.index.findByType(_query.entityType)); diff --git a/tests/mesh/Address.as b/tests/mesh/Address.as index 306bc67..61924f2 100644 --- a/tests/mesh/Address.as +++ b/tests/mesh/Address.as @@ -1,8 +1,14 @@ package mesh { - public class Address + import flash.utils.IDataInput; + import flash.utils.IDataOutput; + import flash.utils.IExternalizable; + + [RemoteClass(alias="mesh.Address")] + + public class Address implements IExternalizable { - public function Address(street:String, city:String) + public function Address(street:String = "", city:String = "") { _street = street; _city = city; @@ -11,7 +17,19 @@ package mesh public function equals(address:Address):Boolean { return street == address.street && - city == address.city; + city == address.city; + } + + public function readExternal(input:IDataInput):void + { + _street = input.readUTF(); + _city = input.readUTF(); + } + + public function writeExternal(output:IDataOutput):void + { + output.writeUTF(street); + output.writeUTF(city); } private var _street:String; diff --git a/tests/mesh/Customer.as b/tests/mesh/Customer.as index 558b708..c4de926 100644 --- a/tests/mesh/Customer.as +++ b/tests/mesh/Customer.as @@ -1,6 +1,6 @@ package mesh { - import mesh.core.object.copy; + import mesh.core.object.merge; import mesh.model.validators.PresenceValidator; import mx.collections.IList; @@ -27,11 +27,17 @@ package mesh hasMany("orders", {inverse:"customer", isMaster:true}); } - override public function toObject(options:Object = null):Object + override public function fromObject(object:Object):void { - var result:Object = super.toObject(); - copy(this, result, {includes:["address", "accountId"]}); - return result; + super.fromObject(object); + address = object.address != null ? new Address(object.address.street, object.address.city) : null; + } + + override protected function get serializableOptions():Object + { + var inherited:Object = super.serializableOptions; + inherited.includes = merge(inherited.includes, {address:true}); + return inherited; } } } \ No newline at end of file diff --git a/tests/mesh/Name.as b/tests/mesh/Name.as index 9b5e5fc..44c011f 100644 --- a/tests/mesh/Name.as +++ b/tests/mesh/Name.as @@ -1,8 +1,14 @@ package mesh { - public class Name + import flash.utils.IDataInput; + import flash.utils.IDataOutput; + import flash.utils.IExternalizable; + + [RemoteClass(alias="mesh.Name")] + + public class Name implements IExternalizable { - public function Name(firstName:String, lastName:String) + public function Name(firstName:String = "", lastName:String = "") { _firstName = firstName; _lastName = lastName; @@ -13,6 +19,18 @@ package mesh return firstName == name.firstName && lastName == name.lastName; } + public function readExternal(input:IDataInput):void + { + _firstName = input.readUTF(); + _lastName = input.readUTF(); + } + + public function writeExternal(output:IDataOutput):void + { + output.writeUTF(firstName); + output.writeUTF(lastName); + } + private var _firstName:String; public function get firstName():String { diff --git a/tests/mesh/Person.as b/tests/mesh/Person.as index 4cea92c..26524f0 100644 --- a/tests/mesh/Person.as +++ b/tests/mesh/Person.as @@ -21,5 +21,21 @@ package mesh { super(properties); } + + override public function fromObject(object:Object):void + { + super.fromObject(object); + name = object.name != null ? new Name(object.name.firstName, object.name.lastName) : null; + } + + override protected function get serializableOptions():Object + { + return { + exclude:["state", "storeKey"], + includes:{ + name:true + } + }; + } } } \ No newline at end of file diff --git a/tests/mesh/model/serialization/SerializerTests.as b/tests/mesh/model/serialization/SerializerTests.as index 273184a..a28b0f2 100644 --- a/tests/mesh/model/serialization/SerializerTests.as +++ b/tests/mesh/model/serialization/SerializerTests.as @@ -43,7 +43,7 @@ package mesh.model.serialization [Test] public function testSerializeUnnested():void { - var serialized:Object = _customer.serialize(); + var serialized:Object = _customer.serialize({}); assertThat(serialized.id, equalTo(_customer.id)); assertThat(serialized.age, equalTo(_customer.age)); @@ -76,9 +76,7 @@ package mesh.model.serialization { var serialized:Object = _customer.serialize({ includes:{ - name:{ - only:["firstName", "lastName"] - }, + name:true, address:{only:["street"]}, orders:{ includes:{ diff --git a/tests/mesh/model/store/FindTests.as b/tests/mesh/model/store/FindTests.as new file mode 100644 index 0000000..b9120a2 --- /dev/null +++ b/tests/mesh/model/store/FindTests.as @@ -0,0 +1,61 @@ +package mesh.model.store +{ + import mesh.Name; + import mesh.Person; + import mesh.model.source.FixtureSource; + import mesh.model.source.MultiSource; + + import org.flexunit.assertThat; + import org.hamcrest.collection.array; + import org.hamcrest.object.equalTo; + import org.hamcrest.object.hasProperties; + + public class FindTests + { + private var _jimmyPage:Person; + private var _robertPlant:Person; + private var _store:Store; + + [Before] + public function setup():void + { + _jimmyPage = new Person({ + age: 67, + name: new Name("Jimmy", "Page") + }); + _robertPlant = new Person({ + age: 63, + name: new Name("Robert", "Plant") + }); + + var multiSource:MultiSource = new MultiSource(); + multiSource.map(Person, new FixtureSource(Person, {latency:0})); + + var tempStore:Store = new Store(multiSource); + tempStore.add(_jimmyPage); + tempStore.add(_robertPlant); + tempStore.commit(); + + // Start fresh with an empty store. + _store = new Store(multiSource); + } + + [Test] + public function testFindEntity():void + { + var customer:Person = _store.find(Person, _jimmyPage.id); + assertThat(customer.id, equalTo(_jimmyPage.id)); + assertThat(customer.name, hasProperties({firstName:_jimmyPage.name.firstName, lastName:_jimmyPage.name.lastName})); + } + + [Test] + public function testFindQuery():void + { + var result:ResultList = _store.find(new LocalQuery().on(Person)); + var results:Array = result.toArray(); + assertThat(results.length, equalTo(2)); + assertThat(results, array(hasProperties({id:_jimmyPage.id, name:hasProperties({firstName:_jimmyPage.name.firstName, lastName:_jimmyPage.name.lastName})}), + hasProperties({id:_robertPlant.id, name:hasProperties({firstName:_robertPlant.name.firstName, lastName:_robertPlant.name.lastName})}))); + } + } +} \ No newline at end of file