diff --git a/back/methods/postcode/filter.js b/back/methods/postcode/filter.js new file mode 100644 index 000000000..9986a16c9 --- /dev/null +++ b/back/methods/postcode/filter.js @@ -0,0 +1,77 @@ +const {ParameterizedSQL} = require('loopback-connector'); +const {buildFilter, mergeFilters} = require('vn-loopback/util/filter'); +// const {models} = require('vn-loopback/server/server'); + +module.exports = Self => { + Self.remoteMethod('filter', { + description: + 'Find all postcodes of the model matched by postcode, town, province or country.', + accessType: 'READ', + returns: { + type: ['object'], + root: true, + }, + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + http: {source: 'query'} + }, + { + arg: 'search', + type: 'string', + description: 'Value to filter', + http: {source: 'query'} + }, + ], + http: { + path: `/filter`, + verb: 'GET', + }, + }); + Self.filter = async(ctx, filter, options) => { + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const conn = Self.dataSource.connector; + const where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return {or: [ + {'pc.code': {like: `%${value}%`}}, + {'t.name': {like: `%${value}%`}}, + {'p.name': {like: `%${value}%`}}, + {'c.country': {like: `%${value}%`}} + ] + }; + } + }) ?? {}; + + filter = mergeFilters(ctx.args?.filter ?? {}, {where}); + + const stmts = []; + let stmt; + stmt = new ParameterizedSQL(` + SELECT + pc.code, + t.name as town, + p.name as province, + c.country + FROM + postCode pc + JOIN town t on t.id = pc.townFk + JOIN province p on p.id = t.provinceFk + JOIN country c on c.id = p.countryFk + `); + + stmt.merge(conn.makeSuffix(filter)); + const itemsIndex = stmts.push(stmt) - 1; + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; diff --git a/back/methods/postcode/specs/filter.spec.js b/back/methods/postcode/specs/filter.spec.js new file mode 100644 index 000000000..c393b629a --- /dev/null +++ b/back/methods/postcode/specs/filter.spec.js @@ -0,0 +1,103 @@ +const {models} = require('vn-loopback/server/server'); + +describe('Postcode filter()', () => { + it('should retrieve with no filter', async() => { + const tx = await models.Postcode.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + + }, + }; + const results = await models.Postcode.filter(ctx, options); + + expect(results.length).toBeGreaterThan(0); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should retrieve with filter as postcode', async() => { + const tx = await models.Postcode.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + search: 46, + }, + }; + const results = await models.Postcode.filter(ctx, options); + + expect(results.length).toEqual(4); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should retrieve with filter as city', async() => { + const tx = await models.Postcode.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + search: 'Alz', + }, + }; + const results = await models.Postcode.filter(ctx, options); + + expect(results.length).toEqual(1); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should retrieve with filter as province', async() => { + const tx = await models.Postcode.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + search: 'one', + }, + }; + const results = await models.Postcode.filter(ctx, options); + + expect(results.length).toEqual(4); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should retrieve with filter as country', async() => { + const tx = await models.Postcode.beginTransaction({}); + const options = {transaction: tx}; + + try { + const ctx = { + args: { + search: 'Ec', + }, + }; + const results = await models.Postcode.filter(ctx, options); + + expect(results.length).toEqual(1); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/back/models/postcode.js b/back/models/postcode.js index b08fdaa40..63fd0657f 100644 --- a/back/models/postcode.js +++ b/back/models/postcode.js @@ -1,6 +1,7 @@ let UserError = require('vn-loopback/util/user-error'); module.exports = Self => { + require('../methods/postcode/filter.js')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') return new UserError(`This postcode already exists`);