Commits

vadimtsushko committed c6ded70

Objectory: support for linked objects

  • Participants
  • Parent commits 303ff17

Comments (0)

Files changed (5)

lib/objectory/Objectory.dart

   String className;
   FactoryMethod factoryMethod;
   Set<String> properties;
+  Map<String,String> components;
   Map<String,String> links;  
-  ClassSchema(this.className,this.factoryMethod,List<String> propertyList,
-    [this.links]){
+  ClassSchema(this.className,this.factoryMethod,List<String> propertyList,    
+    [this.components,this.links]){
     properties = new Set<String>.from(propertyList);
+    if (components !== null){
+      properties.addAll(components.getKeys());
+    }
+    if (links !== null){
+      properties.addAll(links.getKeys());
+    }
+
   }
     
 }
       result.id = map["_id"];    
     }      
     ClassSchema classSchema = schemata[className];
+    if (classSchema.components !== null){      
+      classSchema.components.forEach((property,componentClass){
+        PersistentObject component = map2Object(componentClass,map[property]);
+        result.setProperty(property,component);
+        result.clearDirtyStatus();
+      });
+    }
     if (classSchema.links !== null){      
       classSchema.links.forEach((property,linkClass){
-        PersistentObject linkObject = map2Object(linkClass,map[property]);
-        result.setProperty(property,linkObject);  
-        result.clearDirtyStatus();
+      //  print(property);
+        ObjectId linkId = map[property];
+        if (linkId !== null){
+          PersistentObject link = newInstance(linkClass);
+          link.id = linkId;
+          result.setProperty(property,link);
+          result.clearDirtyStatus();
+        }          
       });
     }
     return result;

lib/objectory/PersistentObject.dart

   void init();
   String get type();
   void clearDirtyStatus();
+  Future fetchLink(String property);
+  Future fetchLinks();
 }
 abstract class PersistentObjectBase extends MapProxy implements PersistentObject{  
   bool setupMode;
       var value = args[0];
       var property = function_name.replaceFirst("set:", "");      
       if (schema.properties.contains(property)) {
+        if (schema.links !== null){
+          if (schema.links.containsKey(property)){
+            if (value.id === null){
+              throw "Error setting link property $property. Link object must have not null id";
+            }            
+            value = value.id;
+          }
+        }
         onValueChanging(property, value);
         this[property] = value;
         if (value is InnerPersistentObject){
   void init(){}  
   abstract String get type();
   abstract bool isRoot();
+  Future<PersistentObject> fetchLink(String property, [Map links]){
+    var completer = new Completer<PersistentObject>();
+    if (links === null){
+      links = objectory.getSchema(type).links;
+    }          
+    if (links === null || !links.containsKey(property)){
+      throw "Link $property is not registered on class $type";
+    }
+    var value = map[property];    
+    if (value !== null){
+      objectory.findOne(links[property],{"_id":value}).then((res){
+        map[property] = res;
+        completer.complete(res);
+      });
+    }
+    else
+    {
+      completer.complete(null);
+    }      
+    return completer.future;
+  }
+  Future fetchLinks(){
+    var links = objectory.getSchema(type).links;
+    if (links === null ){
+      throw "Links are not registered on class $type";
+    }
+    var futures = new List<Future>();
+    for (var link in links.getKeys()){
+      futures.add(fetchLink(link,links));
+    }
+    return Futures.wait(futures);
+  }
+
 }
 abstract class RootPersistentObject extends PersistentObjectBase{
    ObjectId id;

tests/objectory/DomainModel.dart

   String lastName;
   Date birthday;
   Address address;  
+  Person father;
+  Person mother;
 }
 interface IAddress{
   String cityName;
     ["cityName","zipCode","streetName"]));
   objectory.registerClass(new ClassSchema('Person',
     ()=>new Person(),
-    ["firstName","lastName","birthday","address"],
-    links: {"address": "Address"}));
+    ["firstName","lastName","birthday"],
+    components: {"address": "Address"},
+    links: {"father": "Person", "mother": "Person"}));
 }

tests/objectory/ObjectoryImplVmTest.dart

     callbackDone();
   });
 }
-
-
+testObjectWithLinks(){
+  Person father = new Person();  
+  father.firstName = 'Father';
+  objectory.save(father);
+  Person son = new Person();  
+  son.firstName = 'Son';
+  son.father = father;
+  objectory.save(son);  
+  objectory.findOne('Person',query().id(son.id)).then((sonFromObjectory){
+    // Links must be fetched before use.
+    Expect.throws(()=>sonFromObjectory.father.firstName);
+    expect(sonFromObjectory.mother).equals(null);
+    sonFromObjectory.fetchLinks().then((_){
+      expect(sonFromObjectory.father.firstName).equals("Father");
+      expect(sonFromObjectory.mother).equals(null);
+      callbackDone();
+    });    
+  });
+}
 main(){  
   setUpObjectory().then((_) {    
     group("ObjectoryVM", ()  {
       asyncTest("testCompoundObject",1,testCompoundObject);   
       asyncTest("testInsertionAndUpdate",1,testInsertionAndUpdate);         
+      asyncTest("testObjectWithLinks",1,testObjectWithLinks);               
       test("testNewInstanceMethod",testNewInstanceMethod);   
       test("testMap2ObjectMethod",testMap2ObjectMethod);       
     });  

tests/objectory/PersistentObjectTest.dart

 #library("PersistenObjectTests");
 #import("../../lib/objectory/ObjectoryLib_vm.dart");
+#import("../../lib/bson/bson.dart");
 #import('../../third_party/testing/unittest/unittest_vm.dart');
 #source("DomainModel.dart");
 testAuthorCreation(){
   expect(person.isDirty()).isTrue();
   expect(person.address.isDirty()).isTrue();
 }
+testFailOnSettingUnsavedLinkObject(){
+  Person son = new Person();  
+  Person father = new Person();  
+  ;
+  Expect.throws(()=>son.father = father,reason:"Link object must be saved (have ObjectId)");
+}  
 testFailOnAbsentProperty(){
   IAuthor author = new Author();
   Expect.throws(()=>author.sdfsdfsdfgdfgdf,reason:"Must fail on missing property getter");
 }
 
 main(){
+  registerClasses();  
   group("PersistenObjectTests", ()  {
     test("testAuthorCreation",testAuthorCreation);
     test("testSetDirty",testSetDirty);
     test("testCompoundObject",testCompoundObject);
     test("testFailOnAbsentProperty",testFailOnAbsentProperty);
+    test("testFailOnSettingUnsavedLinkObject",testFailOnSettingUnsavedLinkObject);    
   });  
 
 }