Browse Source

-identity map due to async and security reasons; +refs to avoid doubled backref queries in parent-child relations

Ivan Asmer 6 years ago
parent
commit
ce3829419f
2 changed files with 18 additions and 21 deletions
  1. 3 1
      index.js
  2. 15 20
      mm.js

+ 3 - 1
index.js

@@ -28,11 +28,13 @@ const delay       = ms => new Promise(r => setTimeout(r.bind(ms), ms))
     }
     Savable.addClass(Notebook)
     Savable.addClass(User)
+    
 
-    let father = await Savable.m.User.findOne(ObjectID("5c7e830b411baf1efe9f251c"))
+    let father = await Savable.m.User.findOne(ObjectID("5c9559dfbbf3d0049529f70b"))
     console.log(father)
     for (let child of father.children){
         console.log(await child)
+        console.log(child.name, child.dirty)
     }
 
     //let person = new User({

+ 15 - 20
mm.js

@@ -4,24 +4,17 @@ const asynchronize = require('./asynchronize').asynchronize
 let i=0;
 
 module.exports = db => {
-    const identityMap = {}
 
     class Savable {
-        constructor(obj, empty=false){
+        constructor(obj, ref, empty=false){
             //TODO check type for return right class 
             if (obj && obj._id){
                 console.log('savable...')
-                if (!empty){
-                    identityMap[obj._id.toString()] = this
-                }
-                //console.log(identityMap)
-                if (obj._id.toString() in identityMap){
-                    console.log(`in identity map ${obj._id}`)
-                }
             }
 
 
             this._id    = null
+            this._ref   = ref
             this._class = this.__proto__.constructor.name
             this._empty = true
 
@@ -31,16 +24,18 @@ module.exports = db => {
                 this.populate(obj)
                 this._empty = empty
             }
-            if ((obj && obj._id) && (obj._id.toString() in identityMap)) return identityMap[obj._id]
         }
 
 
 
         populate(obj){
-            function convertSavables(obj){
+            const convertSavables = (obj) => {
                 for (const key in obj){
                     if (Savable.isSavable(obj[key])){
-                        obj[key] = Savable.newSavable(obj[key])
+                        obj[key] = (this._ref && 
+                                    obj[key]._id.toString() == this._ref._id.toString()) ? 
+                                                       this._ref : 
+                                                       Savable.newSavable(obj[key], this)
                     }
                     else if (typeof obj[key] === 'object'){
                         convertSavables(obj[key])
@@ -67,14 +62,12 @@ module.exports = db => {
                     delete this.then
                     if (!this._id)    err(new ReferenceError('Id is empty'))
                     if (!this._class) err(new ReferenceError('Class is empty'))
-                    //TODO identityMap check for already loaded object into memory
 
                     this.collection.findOne(this._id).then( data => {
                         if (!data){
                             err(new ReferenceError('Document Not Found'))
                         }
                         this.populate(data)
-                        identityMap[this._id.toString()] = this
                         cb(this)
                     })
                     return this
@@ -179,7 +172,7 @@ module.exports = db => {
                 return result;
             }
 
-            const {_id, _empty, then, ...toSave} = await recursiveSlicer(this)
+            const {_id, _empty, _ref, then, ...toSave} = await recursiveSlicer(this)
 
             //TODO: UPSERT
             if (!this._id){ //first time
@@ -189,7 +182,6 @@ module.exports = db => {
             else { //update
                 await this.collection.updateOne({_id: this._id},  {$set: toSave}).catch(err => console.log('UPDATE ERR', err))
             }
-            identityMap[this._id.toString()] = this
 
             await syncRelations()
         }
@@ -198,18 +190,19 @@ module.exports = db => {
 
 
 
+
         static isSavable(obj){
             //console.log(obj._id, obj._class)
             return obj && obj._id && obj._class
         }
 
-        static newSavable(obj, empty=true){
+        static newSavable(obj, ref, empty=true){
             let className = obj._class || "Savable"
             if (obj.__proto__.constructor === Savable.classes[className]){
                 return obj
             }
             
-            return new Savable.classes[className](obj, empty)
+            return new Savable.classes[className](obj, ref, empty)
         }
 
         static addClass(_class){ //explicit method to add class to Savable registry for instantiate right class later
@@ -230,13 +223,15 @@ module.exports = db => {
                             let cursorGen = asynchronize({s: cursor.stream(), chunkEventName: 'data', endEventName: 'close'})
                             for (const pObj of cursorGen()){
                                 yield new Promise((ok, fail) => 
-                                    pObj.then(obj => ok(Savable.newSavable(obj, false)), 
+                                    pObj.then(obj => ok(Savable.newSavable(obj, null, false)), 
                                               err => fail(err)))
                             }
                         },
                         async findOne(query, projection){
                             let result = await db.collection(_class).findOne(query, projection)
-                            return Savable.newSavable(result, false)
+                            if (result)
+                                return Savable.newSavable(result, null, false)
+                            return result
                         }
                     }
                 },