重构KnexJS多个承诺

时间:2019-04-17 14:49:10

标签: javascript sql knex.js

我正在使用Knexjs和Promise运行多个选择查询。在发送结果之前,我需要所有查询都返回一个值,这已经可以实现。但是我认为代码不是非常优化。

knex(table).select('CRMContactId').where('FCIRecognition', '<', -49.00)
            .then(function(results) {

                data.largeclawbacks = results.length;

                knex(table).select('CRMContactId').where('PlanStatus', 'Out of Force').andWhere(function(){this.whereNot('IncomeType', 'Fund Based Commission').andWhereNot('IncomeType', 'Renewal Commission')})
                    .then(function(results) {

                        data.outofforce = results.length;

                        knex(table).select('CRMContactId').where('GroupOneCaption', 'Tier 2').andWhereNot('Payaways Made/Received', 'Payaway Made')
                            .andWhere((builder) => builder.whereIn('Plantype', ['Flexible Benefits','General Insurance','Group Critical Illness','Group Death In Service','Group Dental Insurance','Group Healthcare Cash Plan','Group Income Protection','Group Life','Group Life;Group Income Protection','Group PMI','Group Travel Insurance']))
                            .andWhereNot('Payable', 0)
                            .then(function(results) {

                                data.tier2 = results.length;

                                knex(table).select('CRMContactId').where((builder) => builder.where('GroupOneCaption', 'Tier 3').orWhere('GroupOneCaption', 'Tier 4')).
                                andWhereNot('Payaways Made/Received', 'Payaway Made')
                                    .andWhere((builder) => builder.whereIn('Plantype', ['Accident Sickness & Unemployment Insurance','AVC','Discretionary Managed Service','Endowment','Enhanced Pension Annuity','Executive Pension Plan','FSAVC','General Investment Account','Income Drawdown','Income Protection','Individual Retirement Account', 'Insurance / Investment Bond','Investment Trust','ISA','Long Term Care','Maximum Investment Plan','Money Purchase Contracted','OEIC / Unit Trust','Offshore Bond','Pension Annuity','Pension Term Assurance','Personal Equity Plan','Personal Pension Plan','Regular Savings Plan','Relevant Life Policy','s226 RAC','s32 Buyout Bond','Savings Account','SIPP','SSAS','Stakeholder Individual','Term Protection','Venture Capital Trust','Whole Of Life','Wrap']))
                                    .andWhereNot('Payable', 0)
                                    .then(function(results) {

                                        data.tier3 = results.length;

                                        knex(table).select('CRMContactId').where('FCIRecognition', '>', 500.00).andWhere('IncomeType', 'Renewal Commission')
                                            .then(function(results) {

                                                data.largerenewal = results.length;

                                                knex.raw(`SELECT ContactName AS Adviser, FORMAT(SUM(Payable),2) AS 'Renewal Income' FROM fci_test WHERE IncomeType IN ("Renewal Commission","Fund Based Commission","Ongoing Fee") AND \`Payaways Made/Received\` != 'Payaway Made' GROUP BY ContactName`)
                                                    .then(function(results){

                                                        data.renewalincome = results[0];
                                                        res.send(data)
                                                    })

                                            })
                                    })
                            })
                    })
            })

我确信有更好的方法对此进行编码并获得相同的结果。

2 个答案:

答案 0 :(得分:1)

我首先要关注可读性,然后才是性能。 通过首先使代码更具可读性,可以更容易地看出可以应用哪种优化。

经过一些重构,我们可以得到类似于以下代码:

knex(table).select('CRMContactId')
  .where('FCIRecognition', '<', -49.00)
  .then(function(results) {

    data.largeclawbacks = results.length;

    knex(table).select('CRMContactId')
      .where('PlanStatus', 'Out of Force')
      .andWhere((builder) => {
        builder.whereNot('IncomeType', 'Fund Based Commission')
          .andWhereNot('IncomeType', 'Renewal Commission');
      })
      .then(function(results) {

        data.outofforce = results.length;

        knex(table).select('CRMContactId')
          .where('GroupOneCaption', 'Tier 2')
          .andWhereNot('Payaways Made/Received', 'Payaway Made')
          .whereIn('Plantype', tier2PlanTypes)
          .andWhereNot('Payable', 0)
          .then(function(results) {

            data.tier2 = results.length;

            knex(table).select('CRMContactId')
              .whereIn('GroupOneCaption', ['Tier 3', 'Tier 4'])
              .andWhereNot('Payaways Made/Received', 'Payaway Made')
              .whereIn('Plantype', tier3PlanTypes)
              .andWhereNot('Payable', 0)
              .then(function(results) {

                data.tier3 = results.length;

                knex(table).select('CRMContactId')
                  .where('FCIRecognition', '>', 500.00)
                  .andWhere('IncomeType', 'Renewal Commission')
                  .then(function(results) {

                    data.largerenewal = results.length;

                    knex.raw(`SELECT ContactName AS Adviser, FORMAT(SUM(Payable),2) AS 'Renewal Income' FROM fci_test 
                              WHERE IncomeType IN ("Renewal Commission","Fund Based Commission","Ongoing Fee") 
                                AND \`Payaways Made/Received\` != 'Payaway Made' GROUP BY ContactName`)
                      .then(function(results){
                          data.renewalincome = results[0];
                          res.send(data)
                      });
                  })
              })
          })
      })
  });

它看起来不多,但是我可以更清楚地看到所有查询都是彼此独立的(我将使用它来进行优化)

之后,进一步进行重构,我将每个查询保存为一个常量,然后使用Promise.all一次发出所有查询,并完成发送查询的方式。

const largeclawbacksQuery = knex(table).select('CRMContactId')
  .where('FCIRecognition', '<', -49.00);

const outofforceQuery = knex(table).select('CRMContactId')
  .where('PlanStatus', 'Out of Force')
  .andWhere((builder) => {
    builder.whereNot('IncomeType', 'Fund Based Commission')
      .andWhereNot('IncomeType', 'Renewal Commission')
  });

const tier2Query = knex(table).select('CRMContactId')
    .where('GroupOneCaption', 'Tier 2')
    .andWhereNot('Payaways Made/Received', 'Payaway Made')
    .whereIn('Plantype', tier2PlanTypes)
    .andWhereNot('Payable', 0);

const tier3Query = knex(table).select('CRMContactId')
  .whereIn('GroupOneCaption', ['Tier 3', 'Tier 4'])
  .andWhereNot('Payaways Made/Received', 'Payaway Made')
  .whereIn('Plantype', tier3PlanTypes)
  .andWhereNot('Payable', 0);

const largerenewalQuery = knex(table).select('CRMContactId')
  .where('FCIRecognition', '>', 500.00)
  .andWhere('IncomeType', 'Renewal Commission');

const renewalincomeQuery = knex.raw(
  `SELECT ContactName AS Adviser, FORMAT(SUM(Payable),2) AS 'Renewal Income' FROM fci_test 
    WHERE IncomeType IN ("Renewal Commission","Fund Based Commission","Ongoing Fee") 
      AND \`Payaways Made/Received\` != 'Payaway Made' GROUP BY ContactName`
);

Promise.all([largeclawbacksQuery, outofforceQuery, tier2Query, tier3Query, largerenewalQuery, renewalincomeQuery])
  .then((result) => {
    res.send({
      largeclawbacks: result[0].length,
      outofforce: result[1].length,
      tier2: results[2].length,
      tier3: results[3].length,
      largerenewal: results[4].length,
      renewalincome: results[4][0],
    });
  });

重要点:

  • whereIn可以链接起来,它们将转换为WHERE afield IN avalues AND bfield IN bvalues的sql
  • 行长可以提高可读性,从而使代码更易于阅读
  • 如果我们将其视为承诺,我们可以等待查询构建器完成查询

进一步的改进:

  • 每个方法(whereIn,where或Where等)返回查询构建器 如here所述,可以通过克隆查询构建器实例来重用部分查询。这可以帮助您为tier2Querytier3Query定义基本查询。
  • 我们可以等待使用更好的API来解决承诺,例如使用promise-all-properties
  • 您可以直接要求COUNT而不是查询所有记录来获取长度值,这将提高性能。

答案 1 :(得分:0)

只是盲目地组织您的诺言并正确地将其按链退还,就像这样:

knex(table)
  .select('CRMContactId')
  .where('FCIRecognition', '<', -49.0)
  .then(function(results) {
    data.largeclawbacks = results.length;

    return knex(table)
      .select('CRMContactId')
      .where('PlanStatus', 'Out of Force')
      .andWhere(function() {
        this.whereNot('IncomeType', 'Fund Based Commission').andWhereNot('IncomeType', 'Renewal Commission');
      });
  })
  .then(function(results) {
    data.outofforce = results.length;

    return knex(table)
      .select('CRMContactId')
      .where('GroupOneCaption', 'Tier 2')
      .andWhereNot('Payaways Made/Received', 'Payaway Made')
      .andWhere(builder =>
        builder.whereIn('Plantype', [
          'Flexible Benefits',
          'General Insurance',
          'Group Critical Illness',
          'Group Death In Service',
          'Group Dental Insurance',
          'Group Healthcare Cash Plan',
          'Group Income Protection',
          'Group Life',
          'Group Life;Group Income Protection',
          'Group PMI',
          'Group Travel Insurance'
        ])
      )
      .andWhereNot('Payable', 0);
  })
  .then(function(results) {
    data.tier2 = results.length;

    return knex(table)
      .select('CRMContactId')
      .where(builder => builder.where('GroupOneCaption', 'Tier 3').orWhere('GroupOneCaption', 'Tier 4'))
      .andWhereNot('Payaways Made/Received', 'Payaway Made')
      .andWhere(builder =>
        builder.whereIn('Plantype', [
          'Accident Sickness & Unemployment Insurance',
          'AVC',
          'Discretionary Managed Service',
          'Endowment',
          'Enhanced Pension Annuity',
          'Executive Pension Plan',
          'FSAVC',
          'General Investment Account',
          'Income Drawdown',
          'Income Protection',
          'Individual Retirement Account',
          'Insurance / Investment Bond',
          'Investment Trust',
          'ISA',
          'Long Term Care',
          'Maximum Investment Plan',
          'Money Purchase Contracted',
          'OEIC / Unit Trust',
          'Offshore Bond',
          'Pension Annuity',
          'Pension Term Assurance',
          'Personal Equity Plan',
          'Personal Pension Plan',
          'Regular Savings Plan',
          'Relevant Life Policy',
          's226 RAC',
          's32 Buyout Bond',
          'Savings Account',
          'SIPP',
          'SSAS',
          'Stakeholder Individual',
          'Term Protection',
          'Venture Capital Trust',
          'Whole Of Life',
          'Wrap'
        ])
      )
      .andWhereNot('Payable', 0);
  })
  .then(function(results) {
    data.tier3 = results.length;

    return knex(table)
      .select('CRMContactId')
      .where('FCIRecognition', '>', 500.0)
      .andWhere('IncomeType', 'Renewal Commission');
  })
  .then(function(results) {
    data.largerenewal = results.length;

    return knex.raw(
      `SELECT ContactName AS Adviser, FORMAT(SUM(Payable),2) AS 'Renewal Income' FROM fci_test WHERE IncomeType IN ("Renewal Commission","Fund Based Commission","Ongoing Fee") AND \`Payaways Made/Received\` != 'Payaway Made' GROUP BY ContactName`
    );
  })
  .then(function(results) {
    data.renewalincome = results[0];
    res.send(data);
  })
  .catch(err => {
    // TODO: send error response
  });

但是,如果您使用async / await来避免需要用于收集结果的全局data对象,那么使用您的编码样式会非常有用。