nodeJs--sequelize Model

前言:

一个大型Web App通常都有几十个映射表,一个映射表就是一个Model。

如果按照各自喜好,那业务代码就不好写。Model不统一,很多代码也无法复用。

所以我们需要一个统一的模型,强迫所有Model都遵守同一个规范,这样不但实现简单,而且容易统一风格。

1、工程结构

nodeJs--sequelize Model_第1张图片

 

2、目录详解

 package.json:项目描叙

{
    "name": "node-model-project",
    "version": "1.0.0",
    "description": "node model sequelize",
    "main": "app.js",
    "scripts": {
        "dev": "node --use_strict app.js"
    },
    "keywords": [
        "sequelize",
        "async"
    ],
    "author": "david pan",
    "dependencies": {
        "node-uuid": "^1.4.8",
        "pg": "^7.4.3",
        "pg-hstore": "^2.3.2",
        "sequelize": "^4.38.0"
    }
}

(1). config --- 数据库配置

config-dev.js 开发数据库配置;config-pub.js(与config-dev.js配置方式相同,只是配置参数根据项目情况而定):


'use strict';

const config = {
    database: 'test', // 使用哪个数据库
    username: 'dbuser', // 用户名
    password: '123456', // 口令
    host: '192.168.3.46', // 主机名
    port: 5432, // 端口号
    dialect: 'postgres'
}

module.exports = config;

 

config.js 配置文件入口:

其中config-override.js 作用是:部署到服务器时,由运维团队配置好config-override.js,以覆盖config-pub.js的默认设置

'use strict';

const devConfig = './config-dev.js';
const pubConfig = './config-pub.js';
const overrideConfig = './config-override.js';

const fs = require('fs');

var config = null;

if (process.env.NODE_ENV === 'dev') {
    console.log(`Load ${devConfig}...`);
    config = require(devConfig);
} else {
    console.log(`Load ${pubConfig}...`);
    config = require(pubConfig);
    try {
        if (fs.statSync(overrideConfig).isFile()) {
            console.log(`Load ${overrideConfig}...`);
            config = Object.assign(config, require(overrideConfig));
        }
    } catch (err) {
        console.log(`Cannot load ${overrideConfig}.`);
    }
}

module.exports = config;

(2). model--- 需要存入的model

User.js:

const db = require('../db');

module.exports = db.defineModel('users', {
    email: {
        type: db.STRING(100),
        unique: true
    },
    passwd: db.STRING(100),
    name: db.STRING(100),
    gender: db.BOOLEAN
});

Pet.js:

const db = require('../db');

module.exports = db.defineModel('pets', {
    ownerId: db.ID,
    name: db.STRING(100),
    gender: db.BOOLEAN,
    birth: db.STRING(10),
});

(3). model.js --- model导入统一处理

// scan all models defined in models:
const fs = require('fs');
const db = require('./db');

let files = fs.readdirSync(__dirname + '/models');

let js_files = files.filter((f)=>{
    return f.endsWith('.js');
}, files);


module.exports = {};

for (let f of js_files) {
    console.log(`import model from file ${f}...`);
    let name = f.substring(0, f.length - 3);
    module.exports[name] = require(__dirname + '/models/' + f);
}

module.exports.sync = () => {
    db.sync();
};

(4). db.js --- model定义规范(项目中可根据实际情况自定义规范)

每个Model必须遵守一套规范:

  1. 统一主键,名称必须是id,类型必须是STRING(50)

  2. 主键可以自己指定,也可以由框架自动生成(如果为null或undefined);

  3. 所有字段默认为NOT NULL,除非显式指定;

  4. 统一timestamp机制,每个Model必须有createdAtupdatedAtversion,分别记录创建时间、修改时间和版本号。其中,createdAtupdatedAtBIGINT存储时间戳,最大的好处是无需处理时区,排序方便。version每次修改时自增。

所以,我们不要直接使用Sequelize的API,而是通过db.js间接地定义Model。

const Sequelize = require('sequelize');

const uuid = require('node-uuid');

const config = require('./config/config');

console.log('init sequelize...');

function generateId() {
    return uuid.v4();
}

var sequelize = new Sequelize(config.database, config.username, config.password, {
    host: config.host,
    dialect: config.dialect,
    pool: {
        max: 5,
        min: 0,
        idle: 10000
    }
});

const ID_TYPE = Sequelize.STRING(50);

function defineModel(name, attributes) {
    var attrs = {};
    for (let key in attributes) {
        let value = attributes[key];
        if (typeof value === 'object' && value['type']) {
            value.allowNull = value.allowNull || false;
            attrs[key] = value;
        } else {
            attrs[key] = {
                type: value,
                allowNull: false
            };
        }
    }
    attrs.id = {
        type: ID_TYPE,
        primaryKey: true
    };
    attrs.createdAt = {
        type: Sequelize.BIGINT,
        allowNull: false
    };
    attrs.updatedAt = {
        type: Sequelize.BIGINT,
        allowNull: false
    };
    attrs.version = {
        type: Sequelize.BIGINT,
        allowNull: false
    };
   
    return sequelize.define(name, attrs, {
        tableName: name,
        timestamps: false,
        hooks: {
            beforeValidate: function (obj) {
                let now = Date.now();
                if (obj.isNewRecord) {
                    console.log('will create entity...' + obj);
                    if (!obj.id) {
                        obj.id = generateId();
                    }
                    obj.createdAt = now;
                    obj.updatedAt = now;
                    obj.version = 0;
                } else {
                    console.log('will update entity...');
                    obj.updatedAt = now;
                    obj.version++;
                }
            }
        }
    });
}

const TYPES = ['STRING', 'INTEGER', 'BIGINT', 'TEXT', 'DOUBLE', 'DATEONLY', 'BOOLEAN'];

var exp = {
    defineModel: defineModel,
    sync: () => {
        // only allow create ddl in non-production environment:
        if (process.env.NODE_ENV !== 'production') {
            sequelize.sync({ force: true });
        } else {
            throw new Error('Cannot sync() when NODE_ENV is set to \'production\'.');
        }
    }
};

for (let type of TYPES) {
    exp[type] = Sequelize[type];
}

exp.ID = ID_TYPE;
exp.generateId = generateId;

module.exports = exp;

User就具有emailpasswdnamegender这4个业务字段。idcreatedAtupdatedAtversion应该自动加上,而不是每个Model都去重复定义。

(5).app.js --- 项目入口(业务逻辑)

const model = require('./model');

let
    Pet = model.Pet,
    User = model.User;

(async () => {
    var user = await User.create({
        name: 'John',
        gender: false,
        email: 'john-' + Date.now() + '@garfield.pet',
        passwd: 'hahaha'
    });
    console.log('created: ' + JSON.stringify(user));
    var cat = await Pet.create({
        ownerId: user.id,
        name: 'Garfield',
        gender: false,
        birth: '2007-07-09',
    });
    console.log('created: ' + JSON.stringify(cat));
    var dog = await Pet.create({
        ownerId: user.id,
        name: 'Odie',
        gender: false,
        birth: '2008-08-09',
    });
    console.log('created: ' + JSON.stringify(dog));
})();

 

你可能感兴趣的:(nodeJs)