Commits

vadimtsushko committed 7057331

First shot at Objectory

  • Participants
  • Parent commits 3b5710c

Comments (0)

Files changed (16)

   executeMessage(MongoMessage message){
     connection.execute(message);
   }    
-  Future <bool> open(){
+  Future<bool> open(){
     return connection.connect();
   }
   Future<Map> executeDbCommand(MongoMessage message){

File lib/dbcollection.dart

   Cursor find([Map selector = const {}, Map fields = null, Map orderBy, int skip = 0,int limit = 0, bool hint = false, bool explain = false] ){
     return new Cursor(db, this, selector: selector, fields: fields, skip: skip, limit: limit, sort: orderBy);//, [selector, skip, limit,sort, hint, explain]);
   }
-  findOne([Map selector = const {}, Map fields = null, Map orderBy, int skip = 0,int limit = 0, bool hint = false, bool explain = false] ){
+  Future<Map> findOne([Map selector = const {}, Map fields = null, Map orderBy, int skip = 0,int limit = 0, bool hint = false, bool explain = false] ){
     Cursor cursor = find(selector,fields,orderBy,skip,limit,hint,explain);
-    Future result = cursor.nextObject();
+    Future<Map> result = cursor.nextObject();
     cursor.close();
     return result;
   }

File lib/helpers/MapProxy.dart

+class _MapProxy<K,V> implements Map<K,V>{
+  LinkedHashMap map;
+  Queue keys;
+  _MapProxy(): map = new LinkedHashMap();
+  bool containsValue(V value)=>map.containsValue(value);
+  
+  bool containsKey(K key)=>map.containsKey(key);
+  
+  V operator [](K key)=>map[key];
+  
+  void operator []=(K key, V value){
+   map[key]=value;
+  } 
+
+  V putIfAbsent(K key, V ifAbsent())=>map.putIfAbsent(key, ifAbsent);
+  
+  V remove(K key)=>map.remove(key);
+  
+  void clear()=>map.clear();
+
+  void forEach(void f(K key, V value))=>map.forEach(f);
+  
+  Collection<K> getKeys()=>map.getKeys();
+  
+  Collection<V> getValues()=>map.getValues();
+  
+  int get length() => map.length;
+
+  bool isEmpty()=>map.isEmpty();  
+}

File lib/helpers/SelectorBuilder.dart

+SelectorBuilder query(){
+  return new SelectorBuilder();
+}
+class SelectorBuilder<K,V> extends _MapProxy<K,V>{
+  toString()=>"SelectorBuilder($map)";
+  SelectorBuilder eq(String fieldName,value){
+    map[fieldName] = value;
+    return this;
+  }
+  SelectorBuilder id(value){
+    map["_id"] = value;
+    return this;
+  }
+  SelectorBuilder ne(String fieldName, value){
+    map[fieldName] = {"\$ne":value};
+    return this;
+  }
+  SelectorBuilder gt(String fieldName,value){
+    map[fieldName] = {"\$gt":value};
+    return this;
+  }
+  SelectorBuilder lt(String fieldName,value){
+    map[fieldName] = {"\$lt":value};
+    return this;
+  }
+  SelectorBuilder gte(String fieldName,value){
+    map[fieldName] = {"\$gte":value};
+    return this;
+  }
+  SelectorBuilder lte(String fieldName,value){    
+    map[fieldName] = {"\$lte":value};
+    return this;
+  }
+  SelectorBuilder all(String fieldName, List values){
+    map[fieldName] = {"\$all":values};
+    return this;
+  }
+  SelectorBuilder nin(String fieldName, List values){
+    map[fieldName] = {"\$nin":values};
+    return this;
+  }
+  SelectorBuilder oneFrom(String fieldName, List values){
+    map[fieldName] = {"\$in":values};
+    return this;
+  } 
+  SelectorBuilder exists(String fieldName){
+    map[fieldName] = {"\$exists":true};
+    return this;    
+  }
+  SelectorBuilder notExists(String fieldName){
+    map[fieldName] = {"\$exists":false};
+    return this;    
+  }
+  SelectorBuilder mod(String fieldName, int value){
+    map[fieldName] = {"\$mod":[value,0]};
+    return this;    
+  }
+  SelectorBuilder match(String fieldName, String pattern,[bool multiLine, bool caseInsensitive, bool dotAll, bool extended]){    
+    map[fieldName] = {'\$regex': new BsonRegexp(pattern,multiLine:multiLine, caseInsensitive:caseInsensitive,
+        dotAll:dotAll,extended:extended)};
+    return this;    
+  }
+  SelectorBuilder range(String fieldName, min, max, [bool minInclude=true, bool maxInclude=true]){
+    Map rangeMap = {};
+    if (minInclude){
+      rangeMap["\$gte"] = min;
+    }
+    else{
+      rangeMap["\$gt"] = min;
+    }
+    if (maxInclude){
+      rangeMap["\$lte"] = max;
+    }
+    else{
+      rangeMap["\$gt"] = max;
+    }
+    map[fieldName] = rangeMap;
+    return this;    
+  }
+  _internQueryMap(){
+    if (!map.containsKey("query")){
+      LinkedHashMap queryMap = new LinkedHashMap.from(map);
+      map.clear();
+      map["query"] = queryMap;
+    }    
+  }
+  SelectorBuilder sortBy(String fieldName, [bool descending=false]){
+    _internQueryMap();
+    if (!map.containsKey("orderby")){
+      map["orderby"] = new LinkedHashMap();  
+    }
+    int order = 1;
+    if (descending){
+      order = -1;
+    }
+    map["orderby"][fieldName] = order;      
+    return this;    
+  }
+  SelectorBuilder comment(String commentStr){
+    _internQueryMap();  
+    map["\$comment"] = commentStr;      
+    return this;    
+  }
+  SelectorBuilder explain(){
+    _internQueryMap();  
+    map["\$explain"] = true;      
+    return this;    
+  }
+  SelectorBuilder snapshot(){
+    _internQueryMap();  
+    map["\$snapshot"] = true;      
+    return this;    
+  }
+  SelectorBuilder showDiskLoc(){
+    _internQueryMap();  
+    map["\$showDiskLoc"] = true;      
+    return this;    
+  }
+  SelectorBuilder returnKey(){
+    _internQueryMap();  
+    map["\$sreturnKey"] = true;      
+    return this;    
+  }  
+  SelectorBuilder where(String javaScriptCode){
+    map["\$where"] = new BsonCode(javaScriptCode);
+    return this;
+  }
+}

File lib/helpers/map_proxy.dart

-class _MapProxy<K,V> implements Map<K,V>{
-  LinkedHashMap map;
-  Queue keys;
-  _MapProxy(): map = {};
-  bool containsValue(V value)=>map.containsValue(value);
-  
-  bool containsKey(K key)=>map.containsKey(key);
-  
-  V operator [](K key)=>map[key];
-  
-  void operator []=(K key, V value){
-   map[key]=value;
-  } 
-
-  V putIfAbsent(K key, V ifAbsent())=>map.putIfAbsent(key, ifAbsent);
-  
-  V remove(K key)=>map.remove(key);
-  
-  void clear()=>map.clear();
-
-  void forEach(void f(K key, V value))=>map.forEach(f);
-  
-  Collection<K> getKeys()=>map.getKeys();
-  
-  Collection<V> getValues()=>map.getValues();
-  
-  int get length() => map.length;
-
-  bool isEmpty()=>map.isEmpty();  
-}

File lib/helpers/selector_builder.dart

-SelectorBuilder query(){
-  return new SelectorBuilder();
-}
-class SelectorBuilder<K,V> extends _MapProxy<K,V>{
-  toString()=>"SelectorBuilder($map)";
-  SelectorBuilder eq(String fieldName,value){
-    map[fieldName] = value;
-    return this;
-  }
-  SelectorBuilder id(value){
-    map["_id"] = value;
-    return this;
-  }
-  SelectorBuilder ne(String fieldName, value){
-    map[fieldName] = {"\$ne":value};
-    return this;
-  }
-  SelectorBuilder gt(String fieldName,value){
-    map[fieldName] = {"\$gt":value};
-    return this;
-  }
-  SelectorBuilder lt(String fieldName,value){
-    map[fieldName] = {"\$lt":value};
-    return this;
-  }
-  SelectorBuilder gte(String fieldName,value){
-    map[fieldName] = {"\$gte":value};
-    return this;
-  }
-  SelectorBuilder lte(String fieldName,value){    
-    map[fieldName] = {"\$lte":value};
-    return this;
-  }
-  SelectorBuilder all(String fieldName, List values){
-    map[fieldName] = {"\$all":values};
-    return this;
-  }
-  SelectorBuilder nin(String fieldName, List values){
-    map[fieldName] = {"\$nin":values};
-    return this;
-  }
-  SelectorBuilder oneFrom(String fieldName, List values){
-    map[fieldName] = {"\$in":values};
-    return this;
-  } 
-  SelectorBuilder exists(String fieldName){
-    map[fieldName] = {"\$exists":true};
-    return this;    
-  }
-  SelectorBuilder notExists(String fieldName){
-    map[fieldName] = {"\$exists":false};
-    return this;    
-  }
-  SelectorBuilder mod(String fieldName, int value){
-    map[fieldName] = {"\$mod":[value,0]};
-    return this;    
-  }
-  SelectorBuilder match(String fieldName, String pattern,[bool multiLine, bool caseInsensitive, bool dotAll, bool extended]){    
-    map[fieldName] = {'\$regex': new BsonRegexp(pattern,multiLine:multiLine, caseInsensitive:caseInsensitive,
-        dotAll:dotAll,extended:extended)};
-    return this;    
-  }
-  SelectorBuilder range(String fieldName, min, max, [bool minInclude=true, bool maxInclude=true]){
-    Map rangeMap = {};
-    if (minInclude){
-      rangeMap["\$gte"] = min;
-    }
-    else{
-      rangeMap["\$gt"] = min;
-    }
-    if (maxInclude){
-      rangeMap["\$lte"] = max;
-    }
-    else{
-      rangeMap["\$gt"] = max;
-    }
-    map[fieldName] = rangeMap;
-    return this;    
-  }
-  _internQueryMap(){
-    if (!map.containsKey("query")){
-      LinkedHashMap queryMap = new LinkedHashMap.from(map);
-      map.clear();
-      map["query"] = queryMap;
-    }    
-  }
-  SelectorBuilder sortBy(String fieldName, [bool descending=false]){
-    _internQueryMap();
-    if (!map.containsKey("orderby")){
-      map["orderby"] = new LinkedHashMap();  
-    }
-    int order = 1;
-    if (descending){
-      order = -1;
-    }
-    map["orderby"][fieldName] = order;      
-    return this;    
-  }
-  SelectorBuilder comment(String commentStr){
-    _internQueryMap();  
-    map["\$comment"] = commentStr;      
-    return this;    
-  }
-  SelectorBuilder explain(){
-    _internQueryMap();  
-    map["\$explain"] = true;      
-    return this;    
-  }
-  SelectorBuilder snapshot(){
-    _internQueryMap();  
-    map["\$snapshot"] = true;      
-    return this;    
-  }
-  SelectorBuilder showDiskLoc(){
-    _internQueryMap();  
-    map["\$showDiskLoc"] = true;      
-    return this;    
-  }
-  SelectorBuilder returnKey(){
-    _internQueryMap();  
-    map["\$sreturnKey"] = true;      
-    return this;    
-  }  
-  SelectorBuilder where(String javaScriptCode){
-    map["\$where"] = new BsonCode(javaScriptCode);
-    return this;
-  }
-}

File lib/mongo.dart

 #source("dbcollection.dart");
 #source("cursor.dart");
 #source("helpers/utils.dart");
-#source("helpers/map_proxy.dart");
-#source("helpers/selector_builder.dart");
+#source("helpers/MapProxy.dart");
+#source("helpers/SelectorBuilder.dart");

File lib/objectory/Objectory.dart

+typedef PersistentObject FactoryMethod();
+interface Objectory{  
+  void registerClass(String className, FactoryMethod fm);
+  Future<PersistentObject> findOne(String className,[Map query]);
+  Future<List<PersistentObject>> find(String className,[Map query]);
+  void save(PersistentObject persistentObject);
+  void remove(PersistentObject persistentObject);
+  Future<bool> connect(String database, [String url]);
+  Future<bool> dropDb();
+}
+class ObjectoryBaseImpl implements Objectory{
+  Map<String,FactoryMethod> factories;
+  ObjectoryBaseImpl(){
+    factories = new  Map<String,FactoryMethod>();
+  }
+  PersistentObject newInstance(String className){
+    if (factories.containsKey(className)){
+      return factories[className]();
+    }
+    throw "Class $className have not been registered in Objectory";
+  }
+  PersistentObject map2Object(String className, Map map){
+    PersistentObject result = newInstance(className);
+    result.map = map;
+    return result;
+  }
+  void registerClass(String className, FactoryMethod fm){
+    factories[className] = fm;
+  }
+}

File lib/objectory/ObjectoryDirectConnectionImpl.dart

+Objectory get objectory() => new ObjectorySingleton._singleton();
+class ObjectorySingleton extends ObjectoryBaseImpl{
+  static Objectory _objectory;
+  ObjectorySingleton._internal();
+  factory ObjectorySingleton._singleton(){
+    if (_objectory === null){
+      _objectory = new ObjectoryDirectConnectionImpl._internal();
+    }
+    return _objectory;
+  }
+}
+class ObjectoryDirectConnectionImpl extends ObjectorySingleton{
+  ObjectoryDirectConnectionImpl._internal():super._internal();
+  Db db;
+  Future<bool> open(String database, [String url]){
+    db = new Db(database);
+    return db.open();
+  }
+  void save(PersistentObject persistentObject){
+    db.collection(persistentObject.type).save(persistentObject);
+  }
+  void remove(PersistentObject persistentObject){
+    db.save(persistentObject);
+  }
+  Future<List<PersistentObject>> find(String className,[Map query]){
+    Completer completer = new Completer();
+    List<PersistentObject> result = new List<PersistentObject>();
+    db.collection(className)
+      .find(query)
+      .each((map){
+        PersistentObject obj = objectory.newInstance(className);
+        obj.map = map;
+        obj.id = map["_id"];
+        result.add(obj);
+      }).then((_) => completer.complete(result));
+    return completer.future;  
+  }
+}

File lib/objectory/ObjectoryLib_vm.dart

+#library("objectory");
+#import("../mongo.dart");
+#import("../bson/bson.dart");
+#source("../helpers/MapProxy.dart");
+#source("PersistentObject.dart");
+#source("Objectory.dart");
+#source("ObjectoryDirectConnectionImpl.dart");

File lib/objectory/PersistentObject.dart

+// noSuchMethod() borrowed from Chris Buckett (chrisbuckett@gmail.com)
+// http://github.com/chrisbu/dartwatch-JsonObject
+class PersistentObject extends _MapProxy{  
+  PersistentObject.fromMap(Map map): super.fromMap(map);
+  Set<String> dirtyFields;
+  ObjectId id;
+  PersistentObject(){        
+    map = null;
+    dirtyFields = new Set<String>();      
+    init();
+//    abstract bool isRoot();
+  }
+  PersistentObject.makeTransient(){
+
+  }
+  setDirty(String fieldName){
+    dirtyFields.add(fieldName);
+  }
+  onValueChanging(String fieldName, newValue){
+    setDirty(fieldName);
+  }
+  isDirty(){
+    return !dirtyFields.isEmpty();
+  }
+
+  noSuchMethod(String function_name, List args) {
+    if (map === null){
+       map =  new LinkedHashMap();
+    }
+    if (args.length == 0 && function_name.startsWith("get:")) {
+      //synthetic getter
+      var property = function_name.replaceFirst("get:", "");
+      if (this.containsKey(property)) {
+        return this[property];
+      }
+      else{
+        return null;
+      }
+    }
+    else if (args.length == 1 && function_name.startsWith("set:")) {
+      //synthetic setter
+      var property = function_name.replaceFirst("set:", "");
+      onValueChanging(property, args[0]);
+      this[property] = args[0];
+      return this[property];
+    }
+    
+    //if we get here, then we've not found it - throw.
+    super.noSuchMethod(function_name, args);
+  }
+  void setProperty(String property, value){
+    noSuchMethod('set:$property',[value]);
+  }
+  Dynamic get(String property){
+    return noSuchMethod('get:$property');
+  }  
+  String toString()=>"$type($map)";
+  void init(){
+  }  
+  abstract String get type();
+  static Future<List<PersistentObject>>find(Map query){
+  }
+  static Future<PersistentObject>findOne(Map query){
+  }  
+}

File tests/objectory/Author.dart

+interface IAuthor{
+  String name;
+  int age;
+  String email;
+}
+class Author extends PersistentObject implements IAuthor{  
+  String get type()=>'Author';
+  set name(String value){
+    if (value is String){
+      value = value.toUpperCase();
+    }      
+    setProperty('name', value);
+  }
+  /*
+  init(){
+    name = null;
+    age = null;
+    email = null;
+  }
+  */
+}

File tests/objectory/ObjectoryBaseImplTest.dart

+#library("ObjectoryBaseImplTest");
+#import("../../lib/objectory/ObjectoryLib_vm.dart");
+#import('../../third_party/testing/unittest/unittest_vm.dart');
+#source("author.dart");
+setUpObjectory(){
+  objectory.registerClass('Author',()=>new Author());
+}
+testNewInstanceMethod(){
+  Author author = objectory.newInstance('Author');
+  expect(author is Author).isTrue();
+  print(author);
+}
+testMap2ObjectMethod(){
+  Map map = {
+    "name": "Vadim",
+    "age": 300,
+    "email": "nobody@know.it"};
+  Author author = objectory.map2Object("Author",map);
+  // Not converted to upperCase because setter has not been invoked
+  expect(author.name).equals("Vadim"); 
+  expect(author.age).equals(300);
+  expect(author.email).equals("nobody@know.it");
+}
+
+main(){  
+  setUpObjectory();
+  group("ObjectoryTests", ()  {
+    test("testNewInstanceMethod",testNewInstanceMethod);   
+    test("testMap2ObjectMethod",testMap2ObjectMethod);       
+  });  
+}

File tests/objectory/ObjectoryImplVmTest.dart

+#library("ObjectoryBaseImplTest");
+#import("../../lib/objectory/ObjectoryLib_vm.dart");
+#import('../../third_party/testing/unittest/unittest_vm.dart');
+#source("author.dart");
+Future<bool> setUpObjectory(){
+  var res = new Completer();
+  objectory.open("ObjectoryTest").then((_){
+    objectory.registerClass('Author',()=>new Author());
+    print("I'm here");
+    res.complete(true);
+  });    
+  return res.future;
+}
+void testInsertion(){
+  Author author = new Author();  
+  author.name = 'Dan';
+  author.age = 3;
+  author.email = 'who@cares.net';
+  objectory.save(author);
+  objectory.find('Author').then((coll){
+    for (Author auth in coll){
+      print("Author: ${auth.id} ${auth.name} ${auth.age}");
+    };
+    callbackDone();
+  });
+}
+
+main(){  
+  setUpObjectory().then((_) {
+    print("And now here. ${objectory.db}");
+    group("ObjectoryTests", ()  {
+      asyncTest("testInsertion",1,testInsertion);   
+    });  
+  });    
+}

File tests/objectory/PersistentObjectTest.dart

+#library("PersistenObjectTests");
+#import("../../lib/objectory/ObjectoryLib_vm.dart");
+#import('../../third_party/testing/unittest/unittest_vm.dart');
+#source("author.dart");
+testAuthorCreation(){
+  Author author = new Author();
+  author.name = 'vadim';
+  author.age = 99;
+  author.email = 'sdf';
+  expect(author.getKeys()[0]).equals("name");
+  expect(author.getKeys()[1]).equals("age");
+  expect(author.getKeys().last()).equals("email");
+  expect(author.getKeys().length).equals(3);
+  expect(author.name).equals('VADIM'); // converted to uppercase by custom  setter;
+}
+testSetDirty(){
+  Author author = new Author();
+  author.name = "Vadim";
+  expect(author.dirtyFields.length).equals(1);
+  expect(author.isDirty()).isTrue();  
+}
+
+main(){
+  group("PersistenObjectTests", ()  {
+    test("testAuthorCreation",testAuthorCreation);
+    test("testSetDirty",testSetDirty);
+  });  
+
+}

File tests/objectory/SimpleTest.dart

+class C1{
+  static final type = 1;
+  static int getType(){
+    return type;
+  }
+  C1(){}
+  factory C1.c2(){
+    return new C2();
+  }
+}
+class C2 extends C1{
+  static final type = 2;
+}
+main(){
+  print(C1.getType());
+  C2 c2 = new C1.c2();
+  print(c2);
+}