#345 - Filter items by tag

This commit is contained in:
Juan 2018-07-09 18:06:25 +02:00
parent 96d755cd21
commit 542d9dca86
7 changed files with 121 additions and 45 deletions

View File

@ -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: '<?',
filter: '<?',
userData: '<?',
userParams: '<?',
primaryKey: '@?',
autoLoad: '<?'
}
@ -232,8 +231,6 @@ function mergeFilters(src, dst) {
res.order = src.order;
if (src.limit)
res.limit = src.limit;
if (src.userData)
res.userData = src.userData;
return res;
}

View File

@ -1,8 +1,8 @@
<vn-crud-model
vn-id="model"
url="/item/api/Items/filter"
filter="::$ctrl.filter"
limit="8"
order="name ASC"
data="items"
auto-load="false">
</vn-crud-model>

View File

@ -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};

View File

@ -21,10 +21,10 @@
value="{{::$ctrl.item.size}}">
</vn-label-value>
<vn-label-value label="Type"
value="{{::$ctrl.item.itemType.name}}">
value="{{::$ctrl.item.type}}">
</vn-label-value>
<vn-label-value label="Buyer"
value="{{::$ctrl.item.itemType.worker.firstName}} {{::$ctrl.item.itemType.worker.name}}">
value="{{::$ctrl.item.firstName}} {{::$ctrl.item.worker}}">
</vn-label-value>
</vn-one>
<vn-horizontal class="buttons">

View File

@ -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);
};
};

View File

@ -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);
});
});
};
};

View File

@ -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);
};