From 3151bca0bd428343719f5e903bc0d10bc068e18a Mon Sep 17 00:00:00 2001
From: Carlos Jimenez <=>
Date: Sun, 14 Oct 2018 17:09:05 +0200
Subject: [PATCH] #710 PROCEDURE vn.ticketComponentUpdateSale() unit test

---
 services/db/tests/vn/buyUltimate.spec.js      |  25 +-
 .../tests/vn/buyUltimateFromInterval.spec.js  |  25 +-
 services/db/tests/vn/logAddWithUser.spec.js   |  28 +-
 .../db/tests/vn/ticketCalculateClon.spec.js   |  80 +++--
 .../vn/ticketComponentUpdateSale.spec.js      | 289 ++++++++++++++++++
 services/loopback/common/models/vn-model.js   |   2 +
 services/loopback/server/server.js            |   2 +
 7 files changed, 397 insertions(+), 54 deletions(-)
 create mode 100644 services/db/tests/vn/ticketComponentUpdateSale.spec.js

diff --git a/services/db/tests/vn/buyUltimate.spec.js b/services/db/tests/vn/buyUltimate.spec.js
index 63539602e2..7e0785baa9 100644
--- a/services/db/tests/vn/buyUltimate.spec.js
+++ b/services/db/tests/vn/buyUltimate.spec.js
@@ -1,25 +1,34 @@
 const app = require(`../../../ticket/server/server`);
+const server = require(`../../../loopback/server/server`);
+const ParameterizedSQL = server.loopbackConnector.ParameterizedSQL;
 
 describe('buyUltimate()', () => {
     const today = new Date();
     it(`should create buyUltimate temporal table and update it's values`, async() => {
+        let stmts = [];
+        let stmt;
+
+        stmts.push('START TRANSACTION');
+
         let params = {
             warehouseFk: 1,
             date: today
         };
 
-        let query = `
-        START TRANSACTION;
-        CALL vn.buyUltimate(?, ?);
-        SELECT * FROM tmp.buyUltimate ORDER BY 'id' DESC;
-        ROLLBACK;`;
-
-        let result = await app.models.Ticket.rawSql(query, [
+        stmt = new ParameterizedSQL('CALL vn.buyUltimate(?, ?)', [
             params.warehouseFk,
             params.date
         ]);
+        stmts.push(stmt);
 
-        let buyUltimateTable = result[2];
+        let buyUltimateTableIndex = stmts.push(`SELECT * FROM tmp.buyUltimate ORDER BY itemFk ASC`) - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        let buyUltimateTable = result[buyUltimateTableIndex];
 
         expect(buyUltimateTable.length).toEqual(4);
 
diff --git a/services/db/tests/vn/buyUltimateFromInterval.spec.js b/services/db/tests/vn/buyUltimateFromInterval.spec.js
index 02402eb870..d558c3cf66 100644
--- a/services/db/tests/vn/buyUltimateFromInterval.spec.js
+++ b/services/db/tests/vn/buyUltimateFromInterval.spec.js
@@ -1,4 +1,6 @@
 const app = require(`../../../ticket/server/server`);
+const server = require(`../../../loopback/server/server`);
+const ParameterizedSQL = server.loopbackConnector.ParameterizedSQL;
 
 describe('buyUltimateFromInterval()', () => {
     let today;
@@ -19,25 +21,32 @@ describe('buyUltimateFromInterval()', () => {
     });
 
     it(`should create a temporal table with it's data`, async() => {
+        let stmts = [];
+        let stmt;
+
+        stmts.push('START TRANSACTION');
+
         let params = {
             warehouseFk: 1,
             started: today,
             ended: today
         };
 
-        let query = `
-        START TRANSACTION;
-        CALL vn.buyUltimateFromInterval(?, ?, ?);
-        SELECT * FROM tmp.buyUltimateFromInterval;
-        ROLLBACK;`;
-
-        let result = await app.models.Ticket.rawSql(query, [
+        stmt = new ParameterizedSQL('CALL vn.buyUltimateFromInterval(?, ?, ?)', [
             params.warehouseFk,
             params.started,
             params.ended
         ]);
+        stmts.push(stmt);
 
-        let buyUltimateFromIntervalTable = result[2];
+        let buyUltimateFromIntervalTableIndex = stmts.push(`SELECT * FROM tmp.buyUltimateFromInterval`) - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        let buyUltimateFromIntervalTable = result[buyUltimateFromIntervalTableIndex];
 
         expect(buyUltimateFromIntervalTable.length).toEqual(2);
 
diff --git a/services/db/tests/vn/logAddWithUser.spec.js b/services/db/tests/vn/logAddWithUser.spec.js
index da85168e28..73b05964c4 100644
--- a/services/db/tests/vn/logAddWithUser.spec.js
+++ b/services/db/tests/vn/logAddWithUser.spec.js
@@ -1,7 +1,14 @@
 const app = require(`../../../ticket/server/server`);
+const server = require(`../../../loopback/server/server`);
+const ParameterizedSQL = server.loopbackConnector.ParameterizedSQL;
 
 describe('logAddWithUser()', () => {
     it('should log any action taken by the user in a table ending in Log', async() => {
+        let stmts = [];
+        let stmt;
+
+        stmts.push('START TRANSACTION');
+
         let params = {
             ticketFk: 1,
             userId: 9,
@@ -10,21 +17,26 @@ describe('logAddWithUser()', () => {
             description: 'we are testing stuff'
         };
 
-        let query = `
-        START TRANSACTION;
-        CALL vn.logAddWithUser(?, ?, ?, ?, ?);
-        SELECT * FROM vn.ticketLog WHERE description = ?;
-        ROLLBACK;`;
-        let result = await app.models.Ticket.rawSql(query, [
+        stmt = new ParameterizedSQL('CALL vn.logAddWithUser(?, ?, ?, ?, ?)', [
             params.ticketFk,
             params.userId,
             params.actionCode,
             params.targetEntity,
-            params.description,
             params.description
         ]);
+        stmts.push(stmt);
 
-        savedDescription = result[2][0].description;
+        stmt = new ParameterizedSQL('SELECT * FROM vn.ticketLog WHERE description = ?', [
+            params.description
+        ]);
+        let ticketLogIndex = stmts.push(stmt) - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        savedDescription = result[ticketLogIndex][0].description;
 
         expect(savedDescription).toEqual(params.description);
     });
diff --git a/services/db/tests/vn/ticketCalculateClon.spec.js b/services/db/tests/vn/ticketCalculateClon.spec.js
index 3e1118b37f..c2e9e2b599 100644
--- a/services/db/tests/vn/ticketCalculateClon.spec.js
+++ b/services/db/tests/vn/ticketCalculateClon.spec.js
@@ -1,8 +1,15 @@
 const app = require(`../../../ticket/server/server`);
+const server = require(`../../../loopback/server/server`);
+const ParameterizedSQL = server.loopbackConnector.ParameterizedSQL;
 
 describe('ticket ticketCalculateClon()', () => {
     const today = new Date();
     it('should add the ticket to the order containing the original ticket', async() => {
+        let stmts = [];
+        let stmt;
+
+        stmts.push('START TRANSACTION');
+
         let params = {
             clientFk: 101,
             shipped: today,
@@ -16,14 +23,7 @@ describe('ticket ticketCalculateClon()', () => {
             originalTicketId: 11
         };
 
-        let query = `
-        START TRANSACTION;
-        CALL vn.ticketCreateWithUser(?, ?, ?, ?, ?, ?, ?, ?, ?, @result);
-        CALL vn.ticketCalculateClon(@result, ?);
-        SELECT * FROM vn.orderTicket WHERE ticketFk = @result;
-        SELECT * FROM tmp.agencyHourGetShipped;
-        ROLLBACK;`;
-        let result = await app.models.Ticket.rawSql(query, [
+        stmt = new ParameterizedSQL('CALL vn.ticketCreateWithUser(?, ?, ?, ?, ?, ?, ?, ?, ?, @result)', [
             params.clientFk,
             params.shipped,
             params.warehouseFk,
@@ -32,21 +32,37 @@ describe('ticket ticketCalculateClon()', () => {
             params.agencyType,
             params.routeFk,
             params.landed,
-            params.userId,
-            params.originalTicketId
+            params.userId
         ]);
+        stmts.push(stmt);
+
+        stmt = new ParameterizedSQL('CALL vn.ticketCalculateClon(@result, ?)', [params.originalTicketId]);
+        stmts.push(stmt);
+
+        let orderIndex = stmts.push(`SELECT * FROM vn.orderTicket WHERE ticketFk = @result`) - 1;
+        let angencyHourIndex = stmts.push(`SELECT * FROM tmp.agencyHourGetShipped`) - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
 
         let expectedOrder = 11;
         let newestTicketIdInFixtures = 21;
 
-        expect(result[3][0].orderFk).toEqual(expectedOrder);
-        expect(result[3][0].ticketFk).toBeGreaterThan(newestTicketIdInFixtures);
-        expect(result[4][0].warehouseFk).toEqual(1);
-        expect(result[4][0].shipped).toBeDefined();
-        expect(result[4][0].landed).toBeDefined();
+        expect(result[orderIndex][0].orderFk).toEqual(expectedOrder);
+        expect(result[orderIndex][0].ticketFk).toBeGreaterThan(newestTicketIdInFixtures);
+        expect(result[angencyHourIndex][0].warehouseFk).toEqual(1);
+        expect(result[angencyHourIndex][0].shipped).toBeDefined();
+        expect(result[angencyHourIndex][0].landed).toBeDefined();
     });
 
     it('should add the ticket to the order containing the original ticket and generate landed value if it was null', async() => {
+        let stmts = [];
+        let stmt;
+
+        stmts.push('START TRANSACTION');
+
         let params = {
             clientFk: 101,
             shipped: today,
@@ -60,14 +76,7 @@ describe('ticket ticketCalculateClon()', () => {
             originalTicketId: 11
         };
 
-        let query = `
-        START TRANSACTION;
-        CALL vn.ticketCreateWithUser(?, ?, ?, ?, ?, ?, ?, ?, ?, @result);
-        CALL vn.ticketCalculateClon(@result, ?);
-        SELECT * FROM vn.orderTicket WHERE ticketFk = @result;
-        SELECT * FROM tmp.agencyHourGetShipped;
-        ROLLBACK;`;
-        let result = await app.models.Ticket.rawSql(query, [
+        stmt = new ParameterizedSQL('CALL vn.ticketCreateWithUser(?, ?, ?, ?, ?, ?, ?, ?, ?, @result)', [
             params.clientFk,
             params.shipped,
             params.warehouseFk,
@@ -76,17 +85,28 @@ describe('ticket ticketCalculateClon()', () => {
             params.agencyType,
             params.routeFk,
             params.landed,
-            params.userId,
-            params.originalTicketId
+            params.userId
         ]);
+        stmts.push(stmt);
+
+        stmt = new ParameterizedSQL('CALL vn.ticketCalculateClon(@result, ?)', [params.originalTicketId]);
+        stmts.push(stmt);
+
+        let orderIndex = stmts.push(`SELECT * FROM vn.orderTicket WHERE ticketFk = @result`) - 1;
+        let angencyHourIndex = stmts.push(`SELECT * FROM tmp.agencyHourGetShipped`) - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
 
         let expectedOrder = 11;
         let newestTicketIdInFixtures = 21;
 
-        expect(result[3][0].orderFk).toEqual(expectedOrder);
-        expect(result[3][0].ticketFk).toBeGreaterThan(newestTicketIdInFixtures);
-        expect(result[4][0].warehouseFk).toEqual(1);
-        expect(result[4][0].shipped).toBeDefined();
-        expect(result[4][0].landed).toBeDefined();
+        expect(result[orderIndex][0].orderFk).toEqual(expectedOrder);
+        expect(result[orderIndex][0].ticketFk).toBeGreaterThan(newestTicketIdInFixtures);
+        expect(result[angencyHourIndex][0].warehouseFk).toEqual(1);
+        expect(result[angencyHourIndex][0].shipped).toBeDefined();
+        expect(result[angencyHourIndex][0].landed).toBeDefined();
     });
 });
diff --git a/services/db/tests/vn/ticketComponentUpdateSale.spec.js b/services/db/tests/vn/ticketComponentUpdateSale.spec.js
new file mode 100644
index 0000000000..a0f63ee8b0
--- /dev/null
+++ b/services/db/tests/vn/ticketComponentUpdateSale.spec.js
@@ -0,0 +1,289 @@
+const app = require(`../../../ticket/server/server`);
+const server = require(`../../../loopback/server/server`);
+const ParameterizedSQL = server.loopbackConnector.ParameterizedSQL;
+
+describe('ticketComponentUpdateSale()', () => {
+    it(`should update the sale price when option ONE using the base components and reclaculate only the ones with isRenewable TRUE`, async() => {
+        let stmts = [];
+        let stmt;
+
+        let params = {
+            warehouseFk: 1,
+            ticketFk: 1
+        };
+
+        stmts.push('START TRANSACTION');
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale');
+
+        // createSaleTempTable code comes from vn.ticketComponentUpdate procedure
+        let createSaleTempTable = `
+            CREATE TEMPORARY TABLE tmp.sale
+                (PRIMARY KEY (saleFk))
+                ENGINE = MEMORY
+                SELECT id AS saleFk, ? warehouseFk
+                    FROM sale s WHERE s.ticketFk = ?
+        `;
+
+        stmt = new ParameterizedSQL(createSaleTempTable, [
+            params.warehouseFk,
+            params.ticketFk
+        ]);
+        stmts.push(stmt);
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent');
+
+        // createTicketComponentTable code comes partially from vn.ticketComponenetCalculate procedure
+        let createTicketComponentTable = `
+            CREATE TEMPORARY TABLE tmp.ticketComponent (
+                warehouseFk INT UNSIGNED NOT NULL,
+                itemFk INT NOT NULL,
+                componentFk INT UNSIGNED NOT NULL,
+                cost DECIMAL(10,4) NOT NULL,
+                INDEX itemWarehouse USING BTREE (itemFk ASC, warehouseFk ASC),
+                UNIQUE INDEX itemWarehouseComponent (itemFk ASC, warehouseFk ASC, componentFk ASC))
+        `;
+
+        stmts.push(createTicketComponentTable);
+
+        let insertTicketComponentTable = `
+            INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
+                VALUES
+                    (1 , 2 , 23 , 999.00),
+                    (1 , 2 , 28 , 2.00),
+                    (1 , 4 , 23 , 999.00),
+                    (1 , 4 , 28 , 1.00)
+        `;
+
+        stmts.push(insertTicketComponentTable);
+
+        let updateComponentTwentyThree = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 23
+        `;
+
+        stmts.push(updateComponentTwentyThree);
+
+        let updateComponentTwentyEight = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 28
+        `;
+
+        stmts.push(updateComponentTwentyEight);
+
+        let priceFixtedToZero = `
+            UPDATE vn.sale
+                SET priceFixed = 0
+                WHERE id = 1
+        `;
+
+        stmts.push(priceFixtedToZero);
+
+        let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('CALL vn.ticketComponentUpdateSale(1)');
+
+        let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        expect(result[firstSalePriceIndexBefore][0].price).toEqual(9.1);
+        expect(result[firstSalePriceIndexAfter][0].price).toEqual(5);
+    });
+
+    it(`should keep the sale price when option TWO using the base components and save the difference in a new component`, async() => {
+        let stmts = [];
+        let stmt;
+
+        let params = {
+            warehouseFk: 1,
+            ticketFk: 1
+        };
+
+        stmts.push('START TRANSACTION');
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale');
+
+        // createSaleTempTable code comes from vn.ticketComponentUpdate procedure
+        let createSaleTempTable = `
+            CREATE TEMPORARY TABLE tmp.sale
+                (PRIMARY KEY (saleFk))
+                ENGINE = MEMORY
+                SELECT id AS saleFk, ? warehouseFk
+                    FROM sale s WHERE s.ticketFk = ?
+        `;
+
+        stmt = new ParameterizedSQL(createSaleTempTable, [
+            params.warehouseFk,
+            params.ticketFk
+        ]);
+        stmts.push(stmt);
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent');
+
+        // createTicketComponentTable code comes partially from vn.ticketComponenetCalculate procedure
+        let createTicketComponentTable = `
+            CREATE TEMPORARY TABLE tmp.ticketComponent (
+                warehouseFk INT UNSIGNED NOT NULL,
+                itemFk INT NOT NULL,
+                componentFk INT UNSIGNED NOT NULL,
+                cost DECIMAL(10,4) NOT NULL,
+                INDEX itemWarehouse USING BTREE (itemFk ASC, warehouseFk ASC),
+                UNIQUE INDEX itemWarehouseComponent (itemFk ASC, warehouseFk ASC, componentFk ASC))
+        `;
+
+        stmts.push(createTicketComponentTable);
+
+        let insertTicketComponentTable = `
+            INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
+                VALUES
+                    (1 , 2 , 23 , 999.00),
+                    (1 , 2 , 28 , 2.00),
+                    (1 , 4 , 23 , 999.00),
+                    (1 , 4 , 28 , 1.00)
+        `;
+
+        stmts.push(insertTicketComponentTable);
+
+        let updateComponentTwentyThree = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 23
+        `;
+
+        stmts.push(updateComponentTwentyThree);
+
+        let updateComponentTwentyEight = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 28
+        `;
+
+        stmts.push(updateComponentTwentyEight);
+
+        let priceFixtedToZero = `
+            UPDATE vn.sale
+                SET priceFixed = 0
+                WHERE id = 1
+        `;
+
+        stmts.push(priceFixtedToZero);
+
+        let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('CALL vn.ticketComponentUpdateSale(2)');
+
+        let addedComponentIndex = stmts.push('SELECT * FROM vn.saleComponent WHERE saleFk = 1 AND componentFk = 17') - 1;
+        let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        expect(result[addedComponentIndex][0].value).toEqual(4.1);
+        expect(result[firstSalePriceIndexBefore][0].price).toEqual(result[firstSalePriceIndexAfter][0].price);
+    });
+
+    it(`should not change the sale price when option SEVEN, instead it stores 80% and 20% of the price in two components and any price difference in a third one`, async() => {
+        let stmts = [];
+        let stmt;
+
+        let params = {
+            warehouseFk: 1,
+            ticketFk: 1
+        };
+
+        stmts.push('START TRANSACTION');
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.sale');
+
+        // createSaleTempTable code comes from vn.ticketComponentUpdate procedure
+        let createSaleTempTable = `
+            CREATE TEMPORARY TABLE tmp.sale
+                (PRIMARY KEY (saleFk))
+                ENGINE = MEMORY
+                SELECT id AS saleFk, ? warehouseFk
+                    FROM sale s WHERE s.ticketFk = ?
+        `;
+
+        stmt = new ParameterizedSQL(createSaleTempTable, [
+            params.warehouseFk,
+            params.ticketFk
+        ]);
+        stmts.push(stmt);
+
+        stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent');
+
+        // createTicketComponentTable code comes partially from vn.ticketComponenetCalculate procedure
+        let createTicketComponentTable = `
+            CREATE TEMPORARY TABLE tmp.ticketComponent (
+                warehouseFk INT UNSIGNED NOT NULL,
+                itemFk INT NOT NULL,
+                componentFk INT UNSIGNED NOT NULL,
+                cost DECIMAL(10,4) NOT NULL,
+                INDEX itemWarehouse USING BTREE (itemFk ASC, warehouseFk ASC),
+                UNIQUE INDEX itemWarehouseComponent (itemFk ASC, warehouseFk ASC, componentFk ASC))
+        `;
+
+        stmts.push(createTicketComponentTable);
+
+        let insertTicketComponentTable = `
+            INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
+                VALUES
+                    (1 , 2 , 29 , 999.00),
+                    (1 , 2 , 28 , 2.00),
+                    (1 , 4 , 29 , 999.00),
+                    (1 , 4 , 28 , 1.00)
+        `;
+
+        stmts.push(insertTicketComponentTable);
+
+        let updateComponentTwentyEight = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 28
+        `;
+
+        stmts.push(updateComponentTwentyEight);
+
+        let updateComponentTwentyNine = `
+            UPDATE vn.saleComponent
+                SET value = '5'
+                WHERE saleFk = 1 AND componentFk = 29
+        `;
+
+        stmts.push(updateComponentTwentyNine);
+
+        let priceFixtedToZero = `
+            UPDATE vn.sale
+                SET priceFixed = 0
+                WHERE id = 1
+        `;
+
+        stmts.push(priceFixtedToZero);
+
+        let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('CALL vn.ticketComponentUpdateSale(7)');
+
+        let componentTwentyEightIndex = stmts.push('SELECT * FROM vn.saleComponent WHERE saleFk = 1 AND componentFk = 28') - 1;
+        let componentTwentyNineIndex = stmts.push('SELECT * FROM vn.saleComponent WHERE saleFk = 1 AND componentFk = 29') - 1;
+        let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
+
+        stmts.push('ROLLBACK');
+
+        let sql = ParameterizedSQL.join(stmts, ';');
+        let result = await app.models.Ticket.rawStmt(sql);
+
+        expect(result[componentTwentyEightIndex][0].value).toEqual(1.6);
+        expect(result[componentTwentyNineIndex][0].value).toEqual(0.4);
+        expect(result[firstSalePriceIndexBefore][0].price).toEqual(result[firstSalePriceIndexAfter][0].price);
+    });
+});
+
diff --git a/services/loopback/common/models/vn-model.js b/services/loopback/common/models/vn-model.js
index bccb23a345..ba27f8e6f4 100644
--- a/services/loopback/common/models/vn-model.js
+++ b/services/loopback/common/models/vn-model.js
@@ -256,6 +256,8 @@ module.exports = function(Self) {
         ]);
     };
 
+    Self.ParameterizedSQL = ParameterizedSQL;
+
     require('../methods/vn-model/installMethod')(Self);
     require('../methods/vn-model/validateBinded')(Self);
     require('../methods/vn-model/rewriteDbError')(Self);
diff --git a/services/loopback/server/server.js b/services/loopback/server/server.js
index b1ccdb6aa7..0fcdfae79a 100644
--- a/services/loopback/server/server.js
+++ b/services/loopback/server/server.js
@@ -4,6 +4,7 @@ let DataSource = require('loopback-datasource-juggler').DataSource;
 let fs = require('fs-extra');
 let i18n = require('i18n');
 let path = require('path');
+const loopbackConnector = require('loopback-connector');
 
 let _resolveConnector = DataSource._resolveConnector;
 
@@ -21,6 +22,7 @@ DataSource._resolveConnector = function(name) {
 
 module.exports = {
     loopback: loopback,
+    loopbackConnector: loopbackConnector,
     boot: vnBoot
 };