Browse Source

basic find promise generator, findOne + asynchronize inside

Ivan Asmer 6 years ago
parent
commit
93e8a38b0f
3 changed files with 206 additions and 84 deletions
  1. 68 0
      asynchronize.js
  2. 90 70
      index.js
  3. 48 14
      mm.js

+ 68 - 0
asynchronize.js

@@ -0,0 +1,68 @@
+function openPromise(){
+    let resolve, reject;
+
+    let np = new Promise((ok, fail) => {resolve = ok; reject = fail});
+
+    np.resolve = resolve;
+    np.reject  = reject;
+
+    return np
+}
+
+function asynchronize({s, chunkEventName, endEventName}){
+    return function* (){
+        const chunks        = {};
+        const promises      = {};
+
+        const clear = i => (delete chunks[i], delete promises[i])
+
+
+        let   chunkCount    = 0;
+        let   promiseCount  = 0;
+        let   end           = false;
+
+        if (!('on' in s)){ //no on method in browser
+            s.on = function(eventName, callback){ //polyfill
+                this['on' + eventName] = callback;
+            }
+        }
+
+
+        //check availability of chunk and promise. If any, resolve promise, and clear both from queue 
+        const chunkAndPromise = i  =>   (i in chunks) && 
+                                        (i in promises) && (
+                                            promises[i].resolve(chunks[i]),
+                                            clear(i))
+
+
+        s.on(chunkEventName, data => {
+            chunks[chunkCount] = data
+
+            chunkAndPromise(chunkCount)
+
+            chunkCount++
+        })
+
+        s.on(endEventName, () => {
+            end = true;
+
+        })
+
+        while (!end || Object.keys(chunks).length){
+
+            let p;
+            promises[promiseCount] = p = openPromise();
+
+            chunkAndPromise(promiseCount)
+
+            promiseCount++;
+            yield p; //yield promise outside
+        }
+
+        for (let i in promises){ //when end and chunks are exhausted
+            promises[i].reject(new Error('End Of S')) //reject all left promises
+        }
+    }
+}
+
+module.exports = {openPromise, asynchronize}

+ 90 - 70
index.js

@@ -9,78 +9,98 @@ const delay       = ms => new Promise(r => setTimeout(r.bind(ms), ms))
     const db          = client.db('mm')
     const Savable     = mm(db)
 
+    class Notebook extends Savable{
+
+    }
+    Savable.addClass(Notebook)
+
+    let notik = await Savable.m.Notebook.findOne(ObjectID('5c7c064d2ed0f4c9ab4cba4e'))
+
+    let SilniyeMans = await Savable.m.Savable.find({ $or: [{surname: 'Silniy'}, {surname: 'Silnaya'}]})
+    for (let man of SilniyeMans){
+        console.log('man', (await man).name, (await man).surname)
+    }
+
+
+
+    //console.log(notik)
+    //notik.ram = 4;
+    //notik.resolution = {width: 1920, height: 1080}
+    //await notik.save()
+    //console.log(await Savable.m.Notebook.findOne(ObjectID('5c7c064d2ed0f4c9ab4cba4e')))
+
     //while(true){
         //await (new Savable({timestamp: (new Date).getTime(), r: Math.random()})).save()
-        let person = new Savable({
-            name: 'Mykola',
-            surname: 'Silniy',
-            phones: ['105', '1'],
-            children: [
-                new Savable({
-                    name: 'Marina',
-                    surname: 'Silnaya',
-                    phones: ['105', '1000503']
-                }),
-                new Savable({
-                    name: 'Andrey',
-                    surname: 'Silniy',
-                    phones: ['103', '1000502']
-                }),
-                new Savable({
-                    name: 'Fedor',
-                    surname: 'Ivanova',
-                    phones: ['102', '1000504'],
-                    notebook: new Savable({
-                        brand: 'dubovo'
-                    })
-                })
-            ]
-        })
-
-        await person.save()
-        console.log(person)
-
-        await delay(3000)
-    //}
-
-    //let person = new Savable()
-    //person._id = ObjectID('5c7bd603ce3cbc409978203e');
-    //console.log(person)
-
-    let child = new Savable({
-        name: 'New One Child',
-        surname: 'Silniy',
-        phones: ['105', '1000506']
-    });
-
-    //console.log(await person)
-    //console.log(await person.children[1])
-    person.children.push(child)
-    child.father = person
-
-    //console.log(person)
-    //console.log(child)
-
-    await person.save()
-
-
-    //console.log(await person.children[3])
-    let p2 =new Savable({_id: ObjectID('5c7bf8f04a3a3299f7deda0d' )}, true) //check for cache hit
-    ;(await new Savable({_id: ObjectID('5c7bf8f04a3a3299f7deda0d' )}, true)) //check for cache hit
-    ;(await p2)
-    console.log('parent 2', p2)
-    console.log(await     p2.children[3]) //check for other hit
-    console.log(await person.children[3].father)
-    console.log(await person.children[3].father.children[1])
-
-    //let obj = {
-        //then(cb){
-            //process.nextTick(() => cb(obj))
-        //}
-    //}
-    //console.log(await obj)
-    //console.log('empty await', await person)//.then(p => console.log(p))
-    //console.log('sub await', (await person.children[0]))//.then(p => console.log(p))
+        //let person = new Savable({
+            //name: 'Mykola',
+            //surname: 'Silniy',
+            //phones: ['105', '1'],
+            //children: [
+                //new Savable({
+                    //name: 'Marina',
+                    //surname: 'Silnaya',
+                    //phones: ['105', '1000503']
+                //}),
+                //new Savable({
+                    //name: 'Andrey',
+                    //surname: 'Silniy',
+                    //phones: ['103', '1000502']
+                //}),
+                //new Savable({
+                    //name: 'Fedor',
+                    //surname: 'Ivanova',
+                    //phones: ['102', '1000504'],
+                    //notebook: new Notebook({
+                        //brand: 'dubovo'
+                    //})
+                //})
+            //]
+        //})
+
+        //await person.save()
+        //console.log(person)
+
+        //await delay(1000)
+    ////}
+
+    ////let person = new Savable()
+    ////person._id = ObjectID('5c7bd603ce3cbc409978203e');
+    ////console.log(person)
+
+    //let child = new Savable({
+        //name: 'New One Child',
+        //surname: 'Silniy',
+        //phones: ['105', '1000506']
+    //});
+
+    ////console.log(await person)
+    ////console.log(await person.children[1])
+    //person.children.push(child)
+    //child.father = person
+
+    ////console.log(person)
+    ////console.log(child)
+
+    //await person.save()
+
+
+    ////console.log(await person.children[3])
+    //let p2 =new Savable({_id: ObjectID('5c7bf8f04a3a3299f7deda0d' )}, true) //check for cache hit
+    //;(await new Savable({_id: ObjectID('5c7bf8f04a3a3299f7deda0d' )}, true)) //check for cache hit
+    //;(await p2)
+    //console.log('parent 2', p2)
+    //console.log(await     p2.children[3]) //check for other hit
+    //console.log(await person.children[3].father)
+    //console.log(await person.children[3].father.children[1])
+
+    ////let obj = {
+        ////then(cb){
+            ////process.nextTick(() => cb(obj))
+        ////}
+    ////}
+    ////console.log(await obj)
+    ////console.log('empty await', await person)//.then(p => console.log(p))
+    ////console.log('sub await', (await person.children[0]))//.then(p => console.log(p))
 
 
 

+ 48 - 14
mm.js

@@ -1,22 +1,19 @@
 const ObjectID    = require("mongodb").ObjectID;
+const asynchronize = require('./asynchronize').asynchronize
 
 module.exports = db => {
     const identityMap = {}
     class Savable {
         constructor(obj, empty=false){
-            if (obj && obj._id){ 
-                if (obj._id.toString() in identityMap){
-                    return identityMap[obj._id]
-                }
-            }
+            //TODO check type for return right class 
+            if ((obj && obj._id) && (obj._id.toString() in identityMap)) return identityMap[obj._id]
 
 
             this._id    = null
             this._class = this.__proto__.constructor.name
             this._empty = true
 
-            Savable.classes                                  = Savable.classes || {}
-            Savable.classes[this.__proto__.constructor.name] = this.__proto__.constructor
+            Savable.addClass(this.__proto__.constructor)
 
             if (obj){
                 this.populate(obj)
@@ -58,13 +55,11 @@ module.exports = db => {
                     if (!this._id)    err(new ReferenceError('Id is empty'))
                     if (!this._class) err(new ReferenceError('Class is empty'))
 
-                    this.collection.findOne({_id: this._id}).then( data => {
+                    this.collection.findOne(_id).then( data => {
                         if (!data){
                             err(new ReferenceError('Document Not Found'))
                         }
-                        console.log('load', this)
                         this.populate(data)
-                        console.log('caching in await', this._id)
                         identityMap[this._id.toString()] = this
                         cb(this)
                     })
@@ -114,7 +109,6 @@ module.exports = db => {
             else { //update
                 await this.collection.updateOne({_id: this._id},  {$set: toSave}).catch(err => console.log('UPDATE ERR', err))
             }
-            console.log('caching in save', this._id)
             identityMap[this._id.toString()] = this
         }
 
@@ -123,14 +117,54 @@ module.exports = db => {
             return obj && obj._id && obj._class
         }
 
-        static newSavable(obj){
+        static newSavable(obj, empty=true){
             let className = obj._class || "Savable"
-            if (obj instanceof Savable.classes[className]){
+            if (obj.__proto__.constructor === Savable.classes[className]){
                 return obj
             }
             
-            return new Savable.classes[className](obj, true)
+            return new Savable.classes[className](obj, empty)
+        }
+
+        static addClass(_class){
+            Savable.classes[_class.name] = _class
+        }
+
+
+        static get m(){
+            return new Proxy({}, {
+                get(obj, _class){
+                    if (_class in obj){
+                        return obj[_class]
+                    }
+
+                    return  obj[_class] = {
+                        * find(query, projection){
+                            let cursor = db.collection(_class).find(query, projection)
+                            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)), 
+                                              err => fail(err)))
+                            }
+                        },
+                        async findOne(query, projection){
+                            let result = await db.collection(_class).findOne(query, projection)
+                            return Savable.newSavable(result, false)
+                        }
+                    }
+                },
+
+                set(obj, propName, value){
+                }
+            })
+
+
+
         }
     }
+
+    Savable.classes                                  = {Savable}
+
     return Savable
 }