筆記:PostgreSQL 、Node.js 、函式計算

阿賀呀發表於2019-02-11

前言

由於工作需要,設計到了阿里雲的函式計算,便記錄下來

  • 技術棧
    • node.js
    • postgresql
    • nodemailer

controller + services

  • 編寫postgresql lib

    不管異常還是正常都返回resolve,在resolve中處理結果,通過success欄位去處理

    const { Pool } = require('pg');
    const config = require('../config/default.js');
    const {
      database: {
        HOST,
        PORT,
        DATABASE,
        USERNAME,
        PASSWORD,
      },
    } = config;
    const pool = new Pool({
      port: PORT,
      host: HOST,
      user: USERNAME,
      password: PASSWORD,
      database: DATABASE,
    });
    /**
     * 
     * @param sql 接收的sql語句
     * @param {Array} values sql語句引數
     * @return { Object } { success: boolean, err || data  }
     */
    const query = async function( sql = 'select NOW()', values = []) {
      return new Promise(resolve => {
        pool.connect((err, client, release) => {
          if (err) {
            return console.error('Error acquiring client', err.stack)
          }
          const params = Array.isArray(values) ? [...values] : [values];
          client.query(sql, params, (error, result) => {
            release();
            if (error) {
              console.error('Error executing query', error.stack);
              resolve({
                success: false,
                error,
              });
            }
            resolve({
              success: true,
              data: result.rows,
            });
          });
        });
      });
    }
    
    module.exports = {
      query,
    }
    複製程式碼
    • config配置檔案如下
      const config = {
        // 資料庫配置
        database: {
          DATABASE: 'databasename',
          USERNAME: 'root',
          PASSWORD: '123456',
          PORT: '3433',
          HOST: 'localhost',
        },
      };
      
      module.exports = config;
      複製程式碼
  • Controller

    • BaseController

    首先編寫一個基類,用於封裝一些通用的方法

    const pool = require('../lib/postgre'); // 匯入封裝好的mysql庫
    const { query } = pool; // 匯入query方法
    class BaseController {
      constructor() {
      }
      // 查詢表內所有資料(非刪除)
      async list() {
        const sql = `select * from ${this.table}`;
        return await query(sql);
      }
      // 執行方法
      async excute(sql, vals = []) {
        return await query(sql, vals);
      }
      // log 方法
      log({func, err}) {
        console.log(`excute function[${func}] occured error : ${err.message || err}`);
      }
    }
    
    module.exports = BaseController;
    
    複製程式碼
    • InqueryController

    具體的業務邏輯Controller類

    const BaseController = require('./BaseController'); // 獲得基類
    // 繼承基類
    class InqueryController extends BaseController {
      constructor() {
        super();
        this.table = 'data_table'; // 賦值table
      }
      // 可以重寫基類的方法,如果有業務需要
      async list() {
        const sql = `select * from ${this.table} ORDER BY created_at DESC `;
        return await this.excute(sql);
      }
      async getUnsendCustomer(vals) {
        const sql = `select * from ${this.table} where created_at > $1 ORDER BY created_at DESC`;
        // 統一在基類呼叫sql引數
        return await this.excute(sql, vals);
      }
      
    }
    module.exports = InqueryController;
    
    複製程式碼
  • Service

    • BaseService

    統一封裝的方法,基類

    // 需要繫結this的方法
    const funcs = [
      'list',
    ]
    class BaseService {
      constructor() {
        this.controller = null;
        // 迴圈遍歷繫結this, 在koa繫結route的時可用到
        funcs.forEach(item => {
          this[item] = this[item].bind(this)
        });
      }
    
      // 查詢方法
      async list(ctx) {
        if (!ctx) {
          return await this.controller.list();
        }
        // controller返回的是一個物件,success(成功為true, 失敗為false), data(成功則有此資料), err(失敗則有此物件)
        const { success: flag, data, error } = await this.controller.list();
        if (flag) {
          // success
          ctx.body = {
            data,
            code: 200,
          }
        } else {
          // failed
          ctx.body = {
            code: 500,
            error,
          };
        }
      }
    }
    
    module.exports = BaseService
    
    複製程式碼
    • InqueryService

    具體的業務邏輯

    // 匯入基類
    const BaseService = require('./BaseService');
    // 匯入對應的controller
    const Controller = require('../controller/InqueryController');
    // 獲取MailSender Service
    const MailService = require('./MailSender');
    const Helper = require('../util/Helper');
    
    const funcs = [
      'unsendUser',
    ];
    // 生成一次controller
    const controller = new Controller();
    class InqueryService extends BaseService {
      constructor() {
        super()
        // 繫結對應的controller
        this.controller = controller;
        funcs.forEach(item => {
          this[item] = this[item].bind(this);
        });
      }
      getMailOpts(i) {
        // you can use the data from database to combine the message
        const message = 'Hello world!';
        return return {
            message,
            // 可以從配置檔案讀取或者oss
            to: 'xxxx@gmail.com',
            subject: 'Hello World',
        };
      }
      
      async unsendUser() {
        const list = await this.controller.list();
        if (list.length > 0) {
          const mailer = new MailService();
          const errorList = [];
          iterateList.forEach(async i => {
            const mailerOption = this.getMailOpts(i);
            const { success, ...rest } = await mailer.sendToAuitAdmin(mailerOption);
            if (!success) {
              errorList.push(rest);
            }
          });
          const lastestTime = iterateList[0].created_at;
          if (errorList.length === 0) {
            return {
                code: 200,
                message: 'Success',
            };
          }
        } else {
          return {
            code: 204,
            message: 'No user found',
          };
        }
      }
    }
    module.exports = new InqueryService();
    
    複製程式碼
  • index.js

函式計算的邏輯

const inqueryService = require('./services/InqueryService'); 
exports.handler = async function(event, context, callback) {
   const result = await inqueryService.unsendUser();
   callback(null, result);
};
複製程式碼

相關文章