Skip to content
This repository was archived by the owner on Feb 11, 2020. It is now read-only.

Commit 13212c5

Browse files
author
Dr. Safi
committed
Refactoring - Aggregated common patterns into decorators.
Cleanning code, removing duplication and refactoring to use decorators.
1 parent f1cbfa2 commit 13212c5

18 files changed

+205
-158
lines changed

class/Application.class.js

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,19 @@ import _ from '../../../node_modules/underscore' // To affect changes of _ to th
88
import { connect } from 'appscript/utilityFunction/middleware/commonDatabaseFunctionality.js'
99
import { add, execute, applyMixin } from 'appscript/utilityFunction/decoratorUtility.js'
1010
import addStaticSubclassToClassArray from 'appscript/module/addStaticSubclassToClassArray.staticMethod'
11+
import { extendedSubclassPattern } from 'appscript/utilityFunction/extendedSubclassPattern.js'
1112

1213
const self =
1314
@add({ to: 'static'}, {
1415
addStaticSubclassToClassArray
1516
})
17+
@extendedSubclassPattern.Superclass()
1618
class Application extends EventEmitter {
1719

18-
static eventEmitter = (new EventEmitter()).setMaxListeners(200) // increase maximum eventliseners (default = 10) // i.e. new EventEmitter()
1920
static rethinkdbConnection = {}
2021
static config = configuration // Array
2122
static frontend;
22-
static extendedSubclass = {
23-
static: []
24-
}
2523

26-
constructor(skipConstructor = false) {
27-
super();
28-
if(skipConstructor) return;
29-
}
30-
3124
static async initialize(/*staticSubclass*/) { // One-time initialization of Applicaiton Class.
3225
console.info(`☕%c Running Application as ${self.config.DEPLOYMENT} - '${self.config.PROTOCOL}${self.config.HOST}'`, self.config.style.green)
3326
self.rethinkdbConnection = await connect()
@@ -37,17 +30,11 @@ class Application extends EventEmitter {
3730
escape: /\{\%-(.+?)\%\}/g
3831
};
3932
await self.eventEmitter.emit('initializationEnd')
33+
await self.eventEmitter.emit('addSubclass')
4034
// if(staticSubclass) self.addStaticSubclassToClassArray(staticSubclass)
4135
}
4236

4337
// Used by extended subclasses:
44-
// Add subclasses to list
45-
static addSubclass({ keyName, Subclass = this } = {}) {
46-
if(!keyName) keyName = Subclass.name
47-
self.eventEmitter.on('initializationEnd', () => {
48-
self.extendedSubclass.static[keyName] = Subclass
49-
})
50-
}
5138

5239
static initializeStaticClass() { // used for extended subclasses
5340
let self = this
@@ -59,7 +46,7 @@ class Application extends EventEmitter {
5946
if(middlewareArray) self.middlewareArray = middlewareArray
6047
await self.middlewareArray.forEach((middleware) => {
6148
self.serverKoa.use(middleware)
62-
}, this);
49+
}, this)
6350
}
6451

6552
static createKoaServer() {

module/reusableNestedUnit/Controller.class.js

Lines changed: 48 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
import commonMethod from './commonMethod.mixin'
2-
const EventEmitter = require('events')
32
import createInstance from 'appscript/module/createInstance.staticMethod'
43
import { usingGenericInstance as populateInstancePropertyFromJson, usingThis as populateInstancePropertyFromJson_this } from 'appscript/module/populateInstancePropertyFromJson.method'
54
import addStaticSubclassToClassArray from 'appscript/module/addStaticSubclassToClassArray.staticMethod'
65
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
7-
import { MultiplePrototypeChain } from 'appscript/module/multiplePrototypeChain'
8-
import { add, execute, applyMixin } from 'appscript/utilityFunction/decoratorUtility.js'
6+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
7+
import { extendedSubclassPattern } from 'appscript/utilityFunction/extendedSubclassPattern.js'
8+
import { superclassInstanceContextPattern } from 'appscript/utilityFunction/superclassInstanceContextPattern.js'
99
import { mix } from 'mixwith'
1010

11+
function cacheInstance({ cacheArrayName, keyArgumentName = 'key' }) { // decorator + proxy
12+
return (target, name, descriptor) => {
13+
let method = target[name]
14+
descriptor.value = new Proxy(method, {
15+
apply: async (target, thisArg, argumentsList) => {
16+
let [{ [keyArgumentName]: key }] = argumentsList // extract key using the specified key parameter name in the method.
17+
let cacheArray = thisArg.instance[cacheArrayName] // Sub array of 'this.instance' in which instances are saved.
18+
let instance;
19+
if(key in cacheArray) {
20+
instance = cacheArray[key]
21+
} else {
22+
instance = await target.apply(thisArg, argumentsList)
23+
cacheArray[key] = instance // add to class cache
24+
}
25+
return instance
26+
}
27+
})
28+
return descriptor
29+
}
30+
}
31+
1132
/**
1233
* @class
1334
* @usage new instance is created for each check.
@@ -19,7 +40,7 @@ export default ({
1940
}) => {
2041
let mixinArray = [/*commonMethod*/]
2142
let self =
22-
@prototypeChainDebug
43+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
2344
@add({ to: 'static'}, {
2445
createInstance,
2546
populateInstancePropertyFromJson,
@@ -28,112 +49,34 @@ export default ({
2849
@add({ to: 'prototype'}, {
2950
populateInstancePropertyFromJson_this
3051
})
31-
@execute({ staticMethod: 'initializeStaticClass' })
32-
@applyMixin({ mixin })
52+
@conditional({ condition: mixin, decorator: applyMixin({ mixin }) })
53+
@extendedSubclassPattern.Superclass()
54+
@superclassInstanceContextPattern()
55+
@conditional({ decorator: extendedSubclassPattern.Subclass(), condition: (methodInstanceName && Superclass) })
3356
class ReusableController extends mix(Superclass).with(...mixinArray) {
3457

35-
static eventEmitter = new EventEmitter() // i.e. new EventEmitter()
36-
static extendedSubclass = {
37-
static: {}
38-
}
39-
40-
static initializeStaticClass(self) {
41-
// Mutation observer on array for debugging purposes.
42-
// self.extendedSubclass.static = new Proxy(self.extendedSubclass.static, {
43-
// set: function(target, property, value, receiver) {
44-
// target[property] = value;
45-
// console.log(self.extendedSubclass.static)
46-
// return true;
47-
// }
48-
// })
49-
50-
if(methodInstanceName && Superclass && Superclass.eventEmitter) {
51-
super.eventEmitter.on('initializationEnd', () => {
52-
let ClassObject = {}
53-
ClassObject[`${methodInstanceName}`] = self
54-
super.addStaticSubclassToClassArray(ClassObject)
55-
})
56-
}
57-
}
58-
59-
static initializeStaticClassControllerLevel() {
60-
let Class = this
61-
Class.eventEmitter.on('initializationEnd', () => {
62-
let ClassObject = {}
63-
ClassObject[`${Class.name}`] = Class
64-
Class.addStaticSubclassToClassArray(ClassObject)
65-
})
66-
}
67-
68-
static createContext(...args) {
69-
let self = this // specific Controller that is a subclass of 'self' (ReusableController)
70-
let contextInstance = new self(false, ...args)
71-
72-
// create a new list object for proxied refrence of subclasses
73-
contextInstance.instanceExtendedSubclass = Object.keys(self.extendedSubclass.static)
74-
.reduce((object, key) => {
75-
// add proxied subclass to the list
76-
object[key] = MultiplePrototypeChain.newChainOnInstanceCreation({
77-
Class: self.extendedSubclass.static[key],
78-
contextInstance
79-
})
80-
return object
81-
}, {})
82-
return contextInstance
83-
}
84-
85-
static callSubclass(name, args) {
86-
return Reflect.construct(self.extendedSubclass.static[name], args)
87-
}
88-
89-
/**
90-
* Properties on instnace object (not on the prototype)
91-
*/
92-
AppInstance; // calling instance that contains the context
93-
instance = {
94-
nestedUnit: [],
95-
unit: [],
96-
}
97-
// conditionTreeKey -> { Json data, properties }
98-
99-
constructor(skipConstructor = false, {portAppInstance}) {
100-
super(true)
101-
if(skipConstructor) return;
102-
if(portAppInstance) this.AppInstance = portAppInstance
103-
}
104-
105-
callSubclass(name, args) {
106-
let contextInstance = this
107-
return Reflect.construct(contextInstance.instanceExtendedSubclass[name], args)
108-
}
109-
58+
@cacheInstance({
59+
cacheArrayName: 'nestedUnit',
60+
keyArgumentName: 'nestedUnitKey'
61+
})
11062
async getNestedUnit({ nestedUnitKey, additionalChildNestedUnit = [], pathPointerKey = null}) {
111-
let nestedUnitInstance;
112-
if(!(nestedUnitKey in this.instance.nestedUnit)) {
113-
nestedUnitInstance = await this.callSubclass('NestedUnit', [nestedUnitKey])
114-
await nestedUnitInstance.initializeInstance()
115-
// add children trees:
116-
nestedUnitInstance.additionalChildNestedUnit = additionalChildNestedUnit
117-
// add pathPointerKey to allow applying additional corresponding additional children.
118-
nestedUnitInstance.pathPointerKey = pathPointerKey
119-
// add to class cache
120-
this.instance.nestedUnit[nestedUnitKey] = nestedUnitInstance
121-
} else {
122-
nestedUnitInstance = this.instance.nestedUnit[nestedUnitKey]
123-
}
124-
return nestedUnitInstance
63+
let instance = await this.callSubclass('NestedUnit', [nestedUnitKey])
64+
await instance.initializeInstance()
65+
// add children trees:
66+
instance.additionalChildNestedUnit = additionalChildNestedUnit
67+
// add pathPointerKey to allow applying additional corresponding additional children.
68+
instance.pathPointerKey = pathPointerKey
69+
return instance
12570
}
12671

127-
async getUnit({unitKey}) {
128-
let unitInstance;
129-
if(!(unitKey in this.instance.unit)) {
130-
unitInstance = await this.callSubclass('Unit', [unitKey])
131-
await unitInstance.initializeInstance()
132-
this.instance.unit[unitKey] = unitInstance
133-
} else {
134-
unitInstance = this.instance.unit[unitKey]
135-
}
136-
return unitInstance
72+
@cacheInstance({
73+
cacheArrayName: 'unit',
74+
keyArgumentName: 'unitKey'
75+
})
76+
async getUnit({ unitKey }) {
77+
let instance = await this.callSubclass('Unit', [unitKey])
78+
await instance.initializeInstance()
79+
return instance
13780
}
13881

13982
}

module/reusableNestedUnit/NestedUnit.class.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
2+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
23

34
export default ({ Superclass }) => {
4-
let self = @prototypeChainDebug
5+
let self =
6+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
57
class RNestedUnit extends Superclass {
68

79
static getDocumentQuery;
810

911
static initializeStaticClass(self, getTableDocument) {
10-
super.initializeStaticClassControllerLevel()
1112
self.getDocumentQuery = getTableDocument
1213
}
1314

14-
constructor(databaseDocumentKey, AppInstance) {
15-
super(false, {portAppInstance: AppInstance})
15+
constructor(databaseDocumentKey) {
16+
super()
1617
this.key = databaseDocumentKey
1718
return this
1819
}

module/reusableNestedUnit/Unit.class.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
2+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
23

34
export default ({ Superclass }) => {
4-
let self = @prototypeChainDebug
5+
let self =
6+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
57
class RUnit extends Superclass {
68

79
static getDocumentQuery;
810

911
static initializeStaticClass(self, getTableDocument) {
1012
self.getDocumentQuery = getTableDocument
11-
super.initializeStaticClassControllerLevel()
1213
}
1314

14-
constructor(databaseDocumentKey, AppInstance) {
15-
super(false, {portAppInstance: AppInstance})
15+
constructor(databaseDocumentKey) {
16+
super()
1617
this.key = databaseDocumentKey
1718
return this
1819
}

module/reusableNestedUnit/entrypoint.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ function createStaticInstanceClasses({
9191
let Unit = UnitFunc({ Superclass: Controller })
9292
SpecificNestedUnitFunc({ Superclass: NestedUnit })
9393
SpecificUnitFunc({ Superclass: Unit })
94-
Controller.eventEmitter.emit('initializationEnd') // register subclasses that are listening for the event to register themselves in extendedSubclass.static array.
94+
Controller.eventEmitter.emit('addSubclass') // register subclasses that are listening for the event to register themselves in extendedSubclass.static array.
9595

9696
// return Controller in which it holds the tree structure.
9797
return Controller

module/reusableNestedUnit/implementation/condition/NestedUnit.class.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import r from 'rethinkdb'
22
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
3-
import { add, execute } from 'appscript/utilityFunction/decoratorUtility.js'
3+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
4+
import { extendedSubclassPattern } from 'appscript/utilityFunction/extendedSubclassPattern.js'
45

56
let getTableDocument = {
67
generate: require('appscript/utilityFunction/database/query/getTableDocument.query.js'),
@@ -11,11 +12,12 @@ import promiseProperRace from 'appscript/utilityFunction/promiseProperRace.js'
1112

1213
export default ({ Superclass }) => {
1314
let self =
14-
@prototypeChainDebug
15+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
1516
@execute({
1617
staticMethod: 'initializeStaticClass',
1718
args: [ getTableDocument.instance['condition_conditionTree'] ]
1819
})
20+
@extendedSubclassPattern.Subclass()
1921
class NestedUnit extends Superclass {
2022
// static getDocumentQuery(connection, conditionTreeKey) {
2123
// getConditionTreeQuery(connection, conditionTreeKey)
@@ -89,7 +91,7 @@ export default ({ Superclass }) => {
8991
let callback;
9092
await promiseProperRace(promiseArray).then((promiseReturnValueArray) => {
9193
callback = promiseReturnValueArray[0] // as only one promise is return in the array.
92-
}).catch(reason => { if(process.env.SZN_DEBUG == 'true' && this.AppInstance.context.headers.debug == 'true') console.log(`🔀⚠️ promiseProperRace rejected because: ${reason}`) })
94+
}).catch(reason => { if(process.env.SZN_DEBUG == 'true' && this.portAppInstance.context.headers.debug == 'true') console.log(`🔀⚠️ promiseProperRace rejected because: ${reason}`) })
9395
return callback ? callback : false;
9496
}
9597

module/reusableNestedUnit/implementation/condition/Unit.class.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
2-
import { add, execute } from 'appscript/utilityFunction/decoratorUtility.js'
2+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
3+
import { extendedSubclassPattern } from 'appscript/utilityFunction/extendedSubclassPattern.js'
34

45
let getTableDocument = {
56
generate: require('appscript/utilityFunction/database/query/getTableDocument.query.js'),
@@ -10,11 +11,12 @@ getTableDocument.instance['condition_conditionImplementation'] = getTableDocumen
1011

1112
export default ({ Superclass }) => {
1213
let self =
13-
@prototypeChainDebug
14+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
1415
@execute({
1516
staticMethod: 'initializeStaticClass',
1617
args: [ getTableDocument.instance['condition_conditionImplementation'] ]
1718
})
19+
@extendedSubclassPattern.Subclass()
1820
class Unit extends Superclass {
1921
async checkCondition() {
2022
// [1] get valueReturningFile
@@ -26,8 +28,8 @@ export default ({ Superclass }) => {
2628
if(!this.conditionResult) {
2729
let expectedReturn = this.expectedReturn
2830
let filePath = this.valueReturningFile.filePath
29-
let returnedValue = await require(filePath)(this.AppInstance)
30-
if(process.env.SZN_DEBUG == 'true' && this.AppInstance.context.headers.debug == 'true') console.log(`🔀 Comparing conditionKey: ${this.key} ${filePath}. \n • expected: ${expectedReturn} == ${returnedValue}. \n • compare result: ${(returnedValue == expectedReturn)} \n \n`)
31+
let returnedValue = await require(filePath)(this.portAppInstance)
32+
if(process.env.SZN_DEBUG == 'true' && this.portAppInstance.context.headers.debug == 'true') console.log(`🔀 Comparing conditionKey: ${this.key} ${filePath}. \n • expected: ${expectedReturn} == ${returnedValue}. \n • compare result: ${(returnedValue == expectedReturn)} \n \n`)
3133
this.conditionResult = (returnedValue == expectedReturn) ? true : false;
3234
}
3335
return this.conditionResult

module/reusableNestedUnit/implementation/condition/controllerMixin.mixin.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Mixin } from 'mixwith'
22
import { classDecorator as prototypeChainDebug} from 'appscript/module/prototypeChainDebug'
3+
import { add, execute, applyMixin, conditional } from 'appscript/utilityFunction/decoratorUtility.js'
34

45
/**
56
* @description Extends a class by super class and adds some common functionality.
67
*/
78
export default Mixin(({ Superclass }) => {
89
let self =
9-
@prototypeChainDebug
10+
@conditional({ decorator: prototypeChainDebug, condition: process.env.SZN_DEBUG })
1011
class ConditionMixin extends Superclass {
1112

1213
/**

0 commit comments

Comments
 (0)