@eyugame/dao
Version:
A modelling tool for RealtimeDatabase(firebase) & Dynamodb(Amazon) & Redis
298 lines (265 loc) • 7.51 kB
JavaScript
/**
* DAO常量 & 工具
*/
;
const joi = require('joi');
const PLATFORM_FIREBASE = 'FIREBASE';
const PLATFORM_AWS = 'AWS';
const DB_REDIS = 'REDIS';
//supported databases
const SUPPORTED_DBS = [PLATFORM_FIREBASE, PLATFORM_AWS, DB_REDIS]
/**
* 是否Firebase平台
*/
function isFirebasePlatform() {
return DB_PLATFORM === PLATFORM_FIREBASE;
}
/**
* 是否AWS平台
*/
function isAWSPlatform() {
return DB_PLATFORM === PLATFORM_AWS;
}
/**
* 是否Redis
*/
function isRedis() {
return DB_PLATFORM === DB_REDIS;
}
/**
* Schema对象
* 用于检查属性冲突
*/
const SCHEMA_ATTRS = {
'hashKey': 'ALL',
'rangeKey': '',
'schema': 'ALL',
'tableName': '',
'ENTITY': '',
'FIREBASE_IGNORED': 'FIREBASE_IGNORED',
'STATIC_METHODS': '',
'INSTANCE_METHODS': '',
'BUILDER': ''
};
/**
* 实体属性 乐观锁字段
*/
const ENTITY_ATTR_VERSION = '_v';
const SCHEMA_FIREBASE_IGNORED = 'FIREBASE_IGNORED';
const SCHEMA_BUILDER = 'builder';
const SCHEMA_INSTANCE_METHODS = 'methods';
/**
* schema缺少属性异常
* @param {String} tableName
* @param {String} attrName
*/
function throwAttrUndefined(tableName, attrName) {
throw new Error(`实体${tableName}缺少${attrName}属性`);
}
/**
* 检查schema
* @param {String} entityName
* @param {Object} schema
*/
function checkSchema(entityName, schema) {
const table = schema.tableName || entityName;
// // 增加JOI验证器
// if (!schema.validator) {
// // 校验器增加版本号支持
// let tmpSchema = Object.assign({}, schema.schema);
// tmpSchema[ENTITY_ATTR_VERSION] = joi.number().positive().optional();
// schema.validator = joi.object(tmpSchema);
// }
//检查schema 属性
for (let attr in SCHEMA_ATTRS) {
let platformSupport = SCHEMA_ATTRS[attr];
if (platformSupport === 'ALL' && !schema[attr]) {
throwAttrUndefined(table, attr);
} else if (PLATFORM_FIREBASE === platformSupport) {
//firebase必须的字段
if (!schema[attr]) {
throwAttrUndefined(table, attr);
}
} else if (PLATFORM_AWS === platformSupport) {
//aws必须的字段
if (!schema[attr]) {
throwAttrUndefined(table, attr);
}
}
}
//检查实体属性 冲突
if (ENTITY_ATTR_VERSION in schema.schema) {
throw new Error(`实体${table}, 属性${ENTITY_ATTR_VERSION}冲突`)
}
//todo:lg
//检查 静态方法 冲突
//检查 对象方法 冲突
if (schema.INSTANCE_METHODS) {
for (let funcName in schema.INSTANCE_METHODS) {
}
}
}
/**
* 重写 entity getter,setter
* @param entity
* @returns {*}
*/
function wrapperEntity(entity) {
//重写 get set
const proxy = new Proxy(entity, {
get: function (targetObj, propKey, receiver) {
const originalAttr = targetObj[propKey];
if (typeof originalAttr === 'function') {
return function (...args) {
return originalAttr.apply(this, args);
}
}
const propValue = targetObj._entity[propKey];
if (propValue === null || propValue === undefined) {
return Reflect.get(targetObj, propKey, receiver);
}
if (DEBUG) {
console.log(`实体${Object.getPrototypeOf(targetObj)._schema.tableName}访问属性${propKey}, 值${JSON.stringify(propValue)}`);
}
return propValue;
},
set: function (targetObj, propKey, value, receiver) {
const selfProto = Object.getPrototypeOf(targetObj)
if (propKey in selfProto._schema.schema) {
targetObj._entity[propKey] = value;
return true;
}
if (propKey === '_entity') {
targetObj._entity = value;
return true;
}
console.log(`实体${selfProto._schema.tableName}非法的属性${propKey}赋值`);
return false;
}
});
return proxy;
}
/**
* 默认的构造器(静态方法)
* @param {object} partitionKey
*/
function entityBuilder(partitionKey) {
return {
...partitionKey
};
}
/**
* 是否空对象
* @param o
* @returns {boolean}
*/
function isEmptyObject(o) {
for (let ignored in o) {
return false;
}
return true;
}
/**
* 获取数据类型
* @param o
* @returns {string}
*/
function getType(o) {
let s = Object.prototype.toString.call(o);
return s.match(/\[object (.*?)\]/)[1].toLowerCase();
}
/**
* 是否数字类型
* @param o
* @returns {boolean}
*/
function isNumber(o) {
return getType(o) === 'number';
}
/**
* 是否异步函数
* @param {function} fn
*/
function isAsyncFunc(fn) {
return '[object AsyncFunction]' === Object.prototype.toString.call(fn);
}
function initDB() {
}
/**
* Set up db
* @param {object} config
*/
function setupDB(config) {
let targetDb = config.db;
if (!targetDb) {
throw new Error('Config参数错误, 无目标DB');
}
targetDb = targetDb.toUpperCase();
if (!SUPPORTED_DBS.includes(targetDb)) {
throw new Error(`Config参数错误, 目标DB: ${targetDb}不支持`);
}
global.DB_PLATFORM = targetDb;
global.TABLE_PREFIX = config.tablePrefix || '';
console.log('--------------------');
console.log('DAO Platform:', DB_PLATFORM);
console.log('TABLE Prefix:', TABLE_PREFIX);
console.log('--------------------');
global.DAO_CONFIG = {};
if (isFirebasePlatform()) {
DAO_CONFIG.rootPath = TABLE_PREFIX ? '/' + TABLE_PREFIX : '/';
} else if (isAWSPlatform()) {
DAO_CONFIG.prefix = TABLE_PREFIX ? TABLE_PREFIX + '_' : '';
DAO_CONFIG.throughput = config.throughput || {
readCapacity: 0,
writeCapacity: 0
};
} else if (isRedis()) {
DAO_CONFIG.connect = {
host: config.host || 'localhost',
port: config.port || 6379,
}
DAO_CONFIG.HASH_KEY_PREFIX = TABLE_PREFIX ? TABLE_PREFIX : '';
if (config.password && config.password.length > 0) {
DAO_CONFIG.auth = {
password: config.password
}
}
}
console.log('DAO set up success...');
}
/**
* 通用的entity => VO
*/
function toVO() {
const result = {};
Object.assign(result, this._entity);
delete result[ENTITY_ATTR_VERSION];
const selfProto = Object.getPrototypeOf(this);
//const firebaseIgnoredAttrs = selfProto._schema.FIREBASE_IGNORED || selfProto._firebaseIgnored;
const rangeKeyName = selfProto._schema.rangeKey;
if (rangeKeyName) {
delete result[rangeKeyName];
} else {
delete result[selfProto._schema.hashKey];
}
return result;
}
module.exports = {
SCHEMA_ATTRS: SCHEMA_ATTRS,
isFirebasePlatform: isFirebasePlatform,
isAWSPlatform: isAWSPlatform,
isRedis: isRedis,
checkSchema: checkSchema,
ENTITY_ATTR_VERSION: ENTITY_ATTR_VERSION,
SCHEMA_FIREBASE_IGNORED: SCHEMA_FIREBASE_IGNORED,
SCHEMA_BUILDER: SCHEMA_BUILDER,
SCHEMA_INSTANCE_METHODS: SCHEMA_INSTANCE_METHODS,
wrapperEntity: wrapperEntity,
isEmptyObject: isEmptyObject,
getType: getType,
isNumber: isNumber,
isAsyncFunc: isAsyncFunc,
entityBuilder: entityBuilder,
setupDB,
toVO
}