diff --git a/client/core/src/components/rest-model/crud-model.js b/client/core/src/components/rest-model/crud-model.js index 614d15aee..1d71dfd61 100644 --- a/client/core/src/components/rest-model/crud-model.js +++ b/client/core/src/components/rest-model/crud-model.js @@ -27,8 +27,7 @@ export default class CrudModel extends ModelProxy { where: mergeWhere(this.link, this.where), include: this.include, order: this.order, - limit: this.limit, - userData: this.userData + limit: this.limit }; let filter = this.filter; @@ -153,7 +152,7 @@ ngModule.component('vnCrudModel', { order: '@?', limit: ' diff --git a/client/item/src/index/index.js b/client/item/src/index/index.js index 9aada522c..6e17a8521 100644 --- a/client/item/src/index/index.js +++ b/client/item/src/index/index.js @@ -8,22 +8,6 @@ class Controller { this.$state = $state; this.$ = $scope; this.itemSelected = null; - - this.filter = { - include: [ - { - relation: 'itemType', - scope: { - fields: ['name', 'workerFk'], - include: { - relation: 'worker', - fields: ['firstName', 'name'] - } - } - } - ], - order: 'name ASC' - }; } exprBuilder(param, value) { @@ -31,10 +15,10 @@ class Controller { case 'search': return /^\d+$/.test(value) ? {id: value} - : {name: {regexp: value}}; + : {name: {like: `%${value}%`}}; case 'name': case 'description': - return {[param]: {regexp: value}}; + return {[param]: {like: `%${value}%`}}; case 'id': case 'typeFk': return {[param]: value}; diff --git a/client/item/src/index/product.html b/client/item/src/index/product.html index 63a413c6b..99419f138 100644 --- a/client/item/src/index/product.html +++ b/client/item/src/index/product.html @@ -21,10 +21,10 @@ value="{{::$ctrl.item.size}}"> + value="{{::$ctrl.item.type}}"> + value="{{::$ctrl.item.firstName}} {{::$ctrl.item.worker}}"> diff --git a/services/loopback/common/methods/item/filter.js b/services/loopback/common/methods/item/filter.js index 1decb9c10..8334e77d8 100644 --- a/services/loopback/common/methods/item/filter.js +++ b/services/loopback/common/methods/item/filter.js @@ -1,3 +1,6 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + module.exports = Self => { Self.remoteMethod('filter', { description: 'Find all instances of the model matched by filter from the data source.', @@ -6,7 +9,7 @@ module.exports = Self => { { arg: 'filter', type: 'Object', - description: 'Filter defining fields, where, include, order, offset, and limit - must be a JSON-encoded string ({"something":"value"})', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', http: {source: 'query'} }, { arg: 'tags', @@ -26,7 +29,29 @@ module.exports = Self => { }); Self.filter = async(filter, tags) => { - console.log(tags); - return await Self.find(filter); + let stmt = new ParameterizedSQL( + `SELECT i.id, i.image, i.name, i.description, i.size, + t.name type, w.firstName, w.name worker + FROM item i + JOIN itemType t ON t.id = i.typeFk + JOIN worker w ON w.id = t.workerFk` + ); + + if (tags) { + let i = 1; + for (let tag of tags) { + if (tag.value == null) continue; + let tAlias = `it${i++}`; + stmt.merge({ + sql: `JOIN itemTag ${tAlias} ON ${tAlias}.itemFk = i.id + AND ${tAlias}.tagFk = ? + AND ${tAlias}.value = ?`, + params: [tag.tagFk, tag.value] + }); + } + } + + stmt.merge(Self.buildSuffix(filter, 'i')); + return Self.rawStmt(stmt); }; }; diff --git a/services/loopback/common/methods/vn-model/rawSql.js b/services/loopback/common/methods/vn-model/rawSql.js deleted file mode 100644 index 9b8a0a07e..000000000 --- a/services/loopback/common/methods/vn-model/rawSql.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = function(Self) { - Self.rawSql = function(query, params, cb) { - var connector = this.dataSource.connector; - return new Promise(function(resolve, reject) { - connector.execute(query, params, function(error, response) { - if (cb) - cb(error, response); - if (error) - reject(error); - else - resolve(response); - }); - }); - }; -}; diff --git a/services/loopback/common/models/vn-model.js b/services/loopback/common/models/vn-model.js index 5d1f4b7be..f1e19351d 100644 --- a/services/loopback/common/models/vn-model.js +++ b/services/loopback/common/models/vn-model.js @@ -1,3 +1,6 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + module.exports = function(Self) { Self.setup = function() { Self.super_.setup.call(this); @@ -162,7 +165,89 @@ module.exports = function(Self) { }; }; - require('../methods/vn-model/rawSql')(Self); + Self.rawSql = function(query, params, cb) { + var connector = this.dataSource.connector; + return new Promise(function(resolve, reject) { + connector.execute(query, params, function(error, response) { + if (cb) + cb(error, response); + if (error) + reject(error); + else + resolve(response); + }); + }); + }; + + Self.rawStmt = function(stmt) { + return this.rawSql(stmt.sql, stmt.params); + }; + + Self.escapeName = function(name) { + return this.dataSource.connector.escapeName(name); + }; + + Self.buildWhere = function(filter, tableAlias) { + let connector = this.dataSource.connector; + let wrappedConnector = Object.create(connector); + wrappedConnector.columnEscaped = function(model, property) { + let sql = tableAlias + ? connector.escapeName(tableAlias) + '.' + : ''; + return sql + connector.columnEscaped(model, property); + }; + + return wrappedConnector.buildWhere(this.modelName, filter.where); + }; + + Self.buildLimit = function(filter) { + let sql = new ParameterizedSQL(''); + this.dataSource.connector.applyPagination(this.modelName, sql, filter); + return sql; + }; + + Self.buildOrderBy = function(filter) { + let order = filter.order; + + if (!order) + return ''; + if (typeof order === 'string') + order = [order]; + + let clauses = []; + + for (let clause of order) { + let sqlOrder = ''; + let t = clause.split(/[\s,]+/); + let names = t[0].split('.'); + + if (names.length > 1) + sqlOrder += this.escapeName(names[0]) + '.'; + sqlOrder += this.escapeName(names[names.length - 1]); + + if (t.length > 1) + sqlOrder += ' ' + (t[1].toUpperCase() == 'ASC' ? 'ASC' : 'DESC'); + + clauses.push(sqlOrder); + } + + return `ORDER BY ${clauses.join(', ')}`; + }; + + Self.buildPagination = function(filter) { + return ParameterizedSQL.join([ + this.buildOrderBy(filter), + this.buildLimit(filter) + ]); + }; + + Self.buildSuffix = function(filter, tableAlias) { + return ParameterizedSQL.join([ + this.buildWhere(filter, tableAlias), + this.buildPagination(filter) + ]); + }; + require('../methods/vn-model/installMethod')(Self); require('../methods/vn-model/validateBinded')(Self); };