#345 - Filter items by tag
This commit is contained in:
parent
96d755cd21
commit
542d9dca86
|
@ -27,8 +27,7 @@ export default class CrudModel extends ModelProxy {
|
||||||
where: mergeWhere(this.link, this.where),
|
where: mergeWhere(this.link, this.where),
|
||||||
include: this.include,
|
include: this.include,
|
||||||
order: this.order,
|
order: this.order,
|
||||||
limit: this.limit,
|
limit: this.limit
|
||||||
userData: this.userData
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let filter = this.filter;
|
let filter = this.filter;
|
||||||
|
@ -153,7 +152,7 @@ ngModule.component('vnCrudModel', {
|
||||||
order: '@?',
|
order: '@?',
|
||||||
limit: '<?',
|
limit: '<?',
|
||||||
filter: '<?',
|
filter: '<?',
|
||||||
userData: '<?',
|
userParams: '<?',
|
||||||
primaryKey: '@?',
|
primaryKey: '@?',
|
||||||
autoLoad: '<?'
|
autoLoad: '<?'
|
||||||
}
|
}
|
||||||
|
@ -232,8 +231,6 @@ function mergeFilters(src, dst) {
|
||||||
res.order = src.order;
|
res.order = src.order;
|
||||||
if (src.limit)
|
if (src.limit)
|
||||||
res.limit = src.limit;
|
res.limit = src.limit;
|
||||||
if (src.userData)
|
|
||||||
res.userData = src.userData;
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
vn-id="model"
|
vn-id="model"
|
||||||
url="/item/api/Items/filter"
|
url="/item/api/Items/filter"
|
||||||
filter="::$ctrl.filter"
|
|
||||||
limit="8"
|
limit="8"
|
||||||
|
order="name ASC"
|
||||||
data="items"
|
data="items"
|
||||||
auto-load="false">
|
auto-load="false">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
|
|
@ -8,22 +8,6 @@ class Controller {
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.$ = $scope;
|
this.$ = $scope;
|
||||||
this.itemSelected = null;
|
this.itemSelected = null;
|
||||||
|
|
||||||
this.filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'itemType',
|
|
||||||
scope: {
|
|
||||||
fields: ['name', 'workerFk'],
|
|
||||||
include: {
|
|
||||||
relation: 'worker',
|
|
||||||
fields: ['firstName', 'name']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
order: 'name ASC'
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exprBuilder(param, value) {
|
exprBuilder(param, value) {
|
||||||
|
@ -31,10 +15,10 @@ class Controller {
|
||||||
case 'search':
|
case 'search':
|
||||||
return /^\d+$/.test(value)
|
return /^\d+$/.test(value)
|
||||||
? {id: value}
|
? {id: value}
|
||||||
: {name: {regexp: value}};
|
: {name: {like: `%${value}%`}};
|
||||||
case 'name':
|
case 'name':
|
||||||
case 'description':
|
case 'description':
|
||||||
return {[param]: {regexp: value}};
|
return {[param]: {like: `%${value}%`}};
|
||||||
case 'id':
|
case 'id':
|
||||||
case 'typeFk':
|
case 'typeFk':
|
||||||
return {[param]: value};
|
return {[param]: value};
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
value="{{::$ctrl.item.size}}">
|
value="{{::$ctrl.item.size}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Type"
|
<vn-label-value label="Type"
|
||||||
value="{{::$ctrl.item.itemType.name}}">
|
value="{{::$ctrl.item.type}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Buyer"
|
<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-label-value>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
<vn-horizontal class="buttons">
|
<vn-horizontal class="buttons">
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('filter', {
|
Self.remoteMethod('filter', {
|
||||||
description: 'Find all instances of the model matched by filter from the data source.',
|
description: 'Find all instances of the model matched by filter from the data source.',
|
||||||
|
@ -6,7 +9,7 @@ module.exports = Self => {
|
||||||
{
|
{
|
||||||
arg: 'filter',
|
arg: 'filter',
|
||||||
type: 'Object',
|
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'}
|
http: {source: 'query'}
|
||||||
}, {
|
}, {
|
||||||
arg: 'tags',
|
arg: 'tags',
|
||||||
|
@ -26,7 +29,29 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.filter = async(filter, tags) => {
|
Self.filter = async(filter, tags) => {
|
||||||
console.log(tags);
|
let stmt = new ParameterizedSQL(
|
||||||
return await Self.find(filter);
|
`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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
Self.setup = function() {
|
Self.setup = function() {
|
||||||
Self.super_.setup.call(this);
|
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/installMethod')(Self);
|
||||||
require('../methods/vn-model/validateBinded')(Self);
|
require('../methods/vn-model/validateBinded')(Self);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue