vendredi 11 octobre 2019

Prototype Pattern Or Properties Pattern in Javscript?

I am learning Patterns in javascript I encountered Prototype Patterns which ideal for making default states in an object.

Example: I am creating Session with PrototypePattern. with some default states and methods like Jwt Sign and Check, getting user account detail's from a database, instance name, etc. so that after Object initialization you have some default handler's and thier configuration which only work's for given request or user.

Code:

'use strict'


/*
IMPORT'S.
*/
import _ from 'underscore' // npm; utility module.
import Jwt from 'jsonwebtoken' // npm: json webtoken library.


/*
PRISMA
 */
import { prisma } from '~prisma' // prisma: database library.



/*
DYNA
 */
import Cache from '~dyna_modules/Cache' // custom: redis cache library.


/*
OBJECT
*/
export default async function Session({ name, request }) {
    // error handling.
    try {
        // properties.
        this.name = name ? name.toUpperCase() : name

        console.log(this, this.prototype)

        // only proceed if request is defined
        // else report failure.
        if (!_.isEmpty(request) && _.isObject(request)) {
            // only proceed if headers
            // authorization is provided
            // else report failure.
            if (request.headers && request.headers.authorization) {
                // local variable.
                let _JwtCheck

                // variable assignment.
                _JwtCheck = this.Jwt.Verify(request.headers.authorization)

                // verify given jwt if is
                // valid token or not.
                if (!_.isEmpty(_JwtCheck) && !(_JwtCheck instanceof Error)) {
                    // local variable.
                    let _Session

                    // variable assignment.
                    _Session = await this.Account({ '$exists': true }).Cache().includes(request.headers.authorization)

                    // if account with given authorization
                    // exist than get user details
                    if (_Session && !(_Session instanceof Error)) {
                        // update instance with
                        // session detail's.
                        this.account = _JwtCheck
                        this.chainValue = _Session

                        // report failure.
                    } else return _Session instanceof Error ? _Session : new Error('Auth token not found in Session. Please login again')

                    // report failure.
                } else return _JwtCheck instanceof Error ? _JwtCheck : new Error('Expected account details but return undefined')

                // report failure.
            }
        }

        // return instance
        return this
    } catch (error) {
        // report failure.
        return error
    }
}



/*
PROTOTYPE
 */
Session.prototype = {
    // properties.
    'name': 'SESSION',
    'chainValue': null,
    'account': null,
    'configuration': {
        'expireIn': '2 days'
    },


    // helper method's.
    'includes': (__include) => { this.chainValue = this.chainValue.includes(__include); return this },


    // jwt handler for handling jwt
    // token's etc.
    'Jwt': {
        'Sign': async (__account) => {
            // local variable.
            let _SignedToken, _UserSessionCache

            console.log(this) // undefined

            // Please note that this is undefined here
            // and we need some configuration values like
            // this.name and this.configuration.expireIn
            // but you can't because this is undefined for
            // that i referenced them directly to prototype
            // this.name 'became' Session.prototype.name
            // this.configuration 'became' Session.protype.configuration 

            // sign toke and update cache.
            _SignedToken = Jwt.sign(__account, process.env.TRUCKPE_SECRET, { 'expiresIn': Session.prototype.configuration.expireIn });
            _UserSessionCache = await Cache({ _id: `${Session.prototype.name}::${__account._id}` })
            _UserSessionCache = _UserSessionCache && _UserSessionCache.Cache && typeof _UserSessionCache.Cache === typeof [] ? _UserSessionCache.Cache : null
            _UserSessionCache = _.isArray(_UserSessionCache) && !_UserSessionCache.includes(_SignedToken) ? [ ..._UserSessionCache, _SignedToken ] : [_SignedToken]

            // run cache again.
            _UserSessionCache = await Cache({ '_id': `SESSION::${__account._id}`, 'whatToCache': _UserSessionCache, 'options': { 'expireIn': Session.prototype.configuration.expireIn } })

            // on successful cacheUpdate reply to
            // client.
            if(!_.isEmpty(_UserSessionCache) && !(_UserSessionCache instanceof Error)) {
                // update chainValue.
                Session.prototype.chainValue = Session.prototype.account = __account

                // register jwt token and
                // return.
                return _SignedToken

                // report failure.
            } else return _UserSessionCache instanceof Error ? _UserSessionCache : new Error('Expected Cache update for session but return was undefined')
        },
        'Verify': async (__token) => {
            // error handling.
            try {
                // local variable.
                let _JwtVerify

                // variable assingment.
                _JwtVerify = await Jwt.verify(__token, process.env.TRUCKPE_SECRET);

                // if _jwtVerify contain's error
                // than report failure else return
                // this.
                if (!_.isEmpty(_JwtVerify) && !(_JwtVerify instanceof Error)) {
                    // update chain value.
                    Session.prototype.chainValue = Session.prototype.account = _JwtVerify

                    // return instance.
                    return Session.prototype

                    // report failure.
                } else return _JwtVerify instanceof Error ? _JwtVerify : new Error(`Caught exception JwtVerify return undefined`)

            } catch (error) {
                // report failure.
                return error
            }
        }
    },


    // account handler for handling
    // user account in prisma
    'Account': async (options) => {
        // error handling.
        try {
            // local variable.
            let _id, _getAccountDetail

            // re-assingment.
            _id = typeof this.chainValue === typeof {} ? this.chainValue['_id'] : typeof this.chainValue === typeof 'String' ? this.chainValue : this.account ? this.account['_id'] : null

            // variable assingment.
            _getAccountDetail = options && options.$exists ? await prisma.account({ _id }).$exists() : await prisma.account({ _id })

            // if getting account detail
            // contain's error than report
            // failure else return account
            // detail's.
            if (_getAccountDetail && !(_getAccountDetail instanceof Error)) {
                // update chainValue.
                this.chainValue = _getAccountDetail

                // return instance.
                return this
            } else return _getAccountDetail instanceof Error ? _getAccountDetail : new Error(`Caught exception while fetching account details from database`)
        } catch (error) {
            // report failure.
            return error
        }
    },


    // cache handler for caching session
    // and other details.
    'Cache': async (options) => {
        // error handling.
        try {
            // local variable.
            let _id, _getCache

            // variable re-assingment.
            _id = typeof this.chainValue === typeof {} ? this.chainValue['_id'] : typeof this.chainValue === typeof 'String' ? this.chainValue : this.account ? this.account['_id'] : null

            // variable assingment.
            _getCache = options && options.save ? await Cache({ '_id': `${this.name}::${_id}`, 'whatToCache': this.chainValue }) : await Cache({ '_id': `${this.name}::${_id}` });

            // if getting cache contains' error
            // than report failure.
            if (!(_getCache instanceof Error)) {
                // update chainValue.
                this.chainValue = _getCache

                // return instanceof
                return this

                // report failure
            } else return _getCache

        } catch  (error) {
            // report failure.
            return error
        }
    }
}

Problem 1:

let _Session = new Session({ request })
console.log(_Session) // { account: null, name: undefined }
console.log(_Session.prototype) // undefined why ?

Problem 2.

_Session.Jwt.Sign({ username: 'bla', 'email': 'lost@stackoverflow.com' })

If you run above code and do console.log(this) inside Session.prototype.Jwt.Sign you will receive undefined I have commented Problem in code. all I want is my prototype properties and method to work as default properties but inside Jwt. Sign you always lost "this" ?

Aucun commentaire:

Enregistrer un commentaire