2016-09-26 21 views
1

我是新來承諾並試圖在NodeJS上構建一個承諾邏輯。我有一個API來跟蹤工作時間。使用PostgreSQL構建具有邏輯的承諾鏈

人們只需輸入他們的PIN碼即可進入時鐘輸入或輸出。

對於CLOCK-IN部分,API()的作用是檢查數據庫(使用pg-promise的PostgreSQL)以查找帶有PIN的僱員ID。如果PIN無效(未找到員工),請用錯誤消息拒絕承諾。然後它必須查找他們的「ClockStatus」來驗證它們是否已經IN或OUT。它可以用檢索員工ID的相同查詢來完成。如果已經在IN,用消息拒絕承諾。然後它必須查找員工的班次ID。之後,它將收集Shift信息以比較時間。 Finnaly,如果將在數據庫中插入一行,並收集上一步收集的信息。

在短:

New Promise 
Get the Employee ID and Clock Status, and Shift ID 
Then 
If No Employee found then reject the promise 
Then 
If Clock Status is already in, reject the promise with a different message 
Then 
Gather informations for the shift 
Then 
Insert a new row in the WorkHour table using Employee info and Shift informations 

我有我的路由器在這裏(使用ExpressJS)

router.post('/clockin', function(req, res) { 
    //Execute the API 
    time 
     .clockin(req.body.pin) 
     .then(function(time) { res.send(time)}) 
     .catch(function(err) { res.status(500).send(err) }); 
}); 

我試圖建立的承諾鏈,但我不想被抓厄運的金字塔。

clockin: function(pin) { 

    // Getting the resourceID from PIN 
    var p = new Promise((resolve, reject) => { 
     if (pin === undefined) { 
      throw new Error('No PIN'); 
     } else { 
      db.any('SELECT id, timeclockstatus From Employee Where PIN = $1', pin) 
      .then((EmployeeInfos) => { 
       return (db.any('select id, timeclockstatus from res_resources where id = $1 ', ResourceID[0].id)) 
      }) 
//****** I'm stuck here 

我想使用ES6的本地承諾。我試圖查找例子,但沒有一個看起來符合我的要求。或者,也許我錯過了什麼... 任何建議?

+0

試試下面的僞代碼。請注意,如果db.any返回承諾,則不需要使用您在發佈的代碼中使用的Promise構造函數反模式 –

+0

在轉換模式之前如何調用'clockin()'(或'clockout')是已知的? –

+0

您的示例中的「ResourceID [0]」引用的內容並不清楚。 –

回答

0

在一種簡化形式,因爲不是一切都從你的情況描述清楚:

router.post('/clockin', function (req, res) { 
    db.task(t=> { 
     var pin = req.body.pin; 
     if (!pin) { 
      throw new Error('No PIN'); 
     } 
     return t.one('SELECT id, timeclockstatus FROM Employee WHERE PIN = $1', pin) 
      .then(data=> { 
       // return another query request, based on `data` 
      }) 
      .then(data=> { 
       // return your insert query as needed, etc... 
      }); 
    }) 
     .then(data=> { 
      // provide successful response; 
     }) 
     .catch(error=> { 
      // provide error response; 
     }); 
}); 
+0

謝謝。我用你的榜樣開始了我。我設法讓它工作。 – Luc

0

如果你是新來的承諾,它也許並不奇怪你卡住。關鍵問題是知道how to access previous results in a then chain,特別是您需要員工信息(來自第一階段)在最後階段的移動信息(來自第三階段)。

正如您在參考資料中看到的,可以使用各種方法。在這些方法中:

  • 「可變上下文狀態」是最簡單但很難看的。
  • 「打破連鎖」是一種可能性。
  • 「嵌套和封閉」是完全可行的,但會給你你試圖避免厄運的金字塔。
  • 「明確的傳遞」(各種配方)很好地與Bluebird承諾,這將是我的選擇在這裏。
clockin: function(pin) { 
    if (!pin) { 
     return Promise.reject(new Error('No PIN')); 
    } else { 
     // STAGE 1 
     let sql = ....; // build sql for retrieving employee record 
     return db.any(sql) 
     .catch(e) => { 
      throw new Error('problem finding employee info'); 
     } 
     // STAGE 2 
     .then((employeeInfo) => { 
      let sql = ....; // build sql for retrieving employee's current status 
      return Promise.all(employeeInfo, db.any(sql)) 
      .catch(e) => { 
       throw new Error('problem finding current status'); 
      }; 
     }) 
     // STAGE 3 
     .spread((employeeInfo, status) => { 
      // a special case here, status === 'IN' requires us to throw. 
      if (status === 'IN') { 
       throw new Error('already IN'); 
      } 
      let sql = ....; // build sql for gathering shift data 
      return Promise.all(employeeInfo, status, db.any(sql)) 
      .catch(e) => { 
       throw new Error('problem finding shift data'); 
      }; 
     }) 
     // STAGE 4 
     .spread((employeeInfo, status, shiftData) => { 
      let time = .....; // calculate `time` using all/any of `employeeInfo', 'status', 'shiftData` 
      let sql = ...; // build sql for inserting new row in the WorkHour table. 
      return db.any(sql) 
      .then(() => [employeeInfo, status, shiftData, time]) // for completeness, make all data available to the caller, though you could return just `time`. 
      .catch((e) => { 
       throw new Error('problem saving new clocking'); 
      }); 
     }); 
    } 
}, 

四個階段制定略有不同,但在本質上是相同的。每個階段:

  • 做一些事情異步,
  • 通行證上所有以前的結果加上自己的結果下跌爲主鏈的成功路徑,
  • 向下傳遞的主鏈上的錯誤路徑有意義的錯誤消息。

請注意使用Promise.all()和(Bluebird's).spread()可使多個結果可用於下一階段。原生ES6承諾可以實現同樣的效果,但上面展示的一些簡單性會丟失。

通過上面的代碼中, '/ clockin' 路由器的功能是:

router.post('/clockin', function(req, res) { 
    //Execute the API 
    time.clockin(req.body.pin) 
    .spread((employeeInfo, status, shiftData, time) => { res.send(time); }) 
    .catch((err) => { res.status(500).send(err) }); // any uncaught errors thrown above will percolate down to here. 
});