feat: WIP advanced filter.

This commit is contained in:
a.bouhuolia
2021-08-10 19:38:36 +02:00
parent aefb89e1c0
commit 23e8e251a1
97 changed files with 2008 additions and 1937 deletions

View File

@@ -1,7 +1,6 @@
import { Service, Inject } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express';
import { param, query } from 'express-validator';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
import { param } from 'express-validator';
import BaseController from './BaseController';
import { ServiceError } from 'exceptions';
import ResourceService from 'services/Resource/ResourceService';
@@ -19,32 +18,15 @@ export default class ResourceController extends BaseController {
router.get(
'/:resource_model/meta',
[...this.resourceModelParamSchema],
[
param('resource_model').exists().trim().escape()
],
this.asyncMiddleware(this.resourceMeta.bind(this)),
this.handleServiceErrors
);
router.get(
'/:resource_model/fields',
[...this.resourceModelParamSchema],
this.validationResult,
asyncMiddleware(this.resourceFields.bind(this)),
this.handleServiceErrors
);
router.get(
'/:resource_model/data',
[...this.resourceModelParamSchema],
this.validationResult,
asyncMiddleware(this.resourceData.bind(this)),
this.handleServiceErrors
);
return router;
}
get resourceModelParamSchema() {
return [param('resource_model').exists().trim().escape()];
}
/**
* Retrieve resource model meta.
* @param {Request} req -
@@ -52,7 +34,7 @@ export default class ResourceController extends BaseController {
* @param {NextFunction} next -
* @returns {Response}
*/
private resourceMeta = (
public resourceMeta = (
req: Request,
res: Response,
next: NextFunction
@@ -73,56 +55,6 @@ export default class ResourceController extends BaseController {
}
};
/**
* Retrieve resource fields of the given resource.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
resourceFields(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { resource_model: resourceModel } = req.params;
try {
// const resourceFields = this.resourcesService.getResourceFields(
// tenantId,
// resourceModel
// );
return res.status(200).send({
resource_fields: [],
});
} catch (error) {
next(error);
}
}
/**
* Retrieve resource data of the give resource based on the given query.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async resourceData(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { resource_model: resourceModel } = req.params;
const filter = req.query;
try {
const resourceData = await this.resourcesService.getResourceData(
tenantId,
resourceModel,
filter
);
return res.status(200).send({
resource_data: this.transfromToResponse(resourceData),
});
} catch (error) {
next(error);
}
}
/**
* Handles service errors.
* @param {Error} error

View File

@@ -23,6 +23,7 @@ export default {
column: 'slug',
fieldType: 'text',
columnable: false,
filterable: false,
},
code: {
name: 'Account code',
@@ -76,6 +77,7 @@ export default {
name: 'Currency',
column: 'currency_code',
fieldType: 'text',
filterable: false,
},
created_at: {
name: 'Created at',

View File

@@ -48,12 +48,12 @@ export default {
fieldType: 'enumeration',
columnable: true,
options: [
{ name: 'Paid', key: 'paid' },
{ name: 'Partially paid', key: 'partially-paid' },
{ name: 'Overdue', key: 'overdue' },
{ name: 'Unpaid', key: 'unpaid' },
{ name: 'Opened', key: 'opened' },
{ name: 'Draft', key: 'draft' },
{ label: 'Paid', key: 'paid' },
{ label: 'Partially paid', key: 'partially-paid' },
{ label: 'Overdue', key: 'overdue' },
{ label: 'Unpaid', key: 'unpaid' },
{ label: 'Opened', key: 'opened' },
{ label: 'Draft', key: 'draft' },
],
filterCustomQuery: StatusFieldFilterQuery,
sortCustomQuery: StatusFieldSortQuery,

View File

@@ -43,6 +43,7 @@ export default {
created_at: {
name: 'Created at',
column: 'created_at',
fieldType: 'date',
},
balance: {
name: 'Balance',
@@ -61,11 +62,13 @@ export default {
fieldType: 'date',
},
currency_code: {
name: 'Curreny',
column: 'currency_code',
fieldType: 'text',
},
status: {
label: 'Status',
name: 'Status',
fieldType: 'enumeration',
options: [
{ key: 'active', label: 'Active' },
{ key: 'inactive', label: 'Inactive' },

View File

@@ -48,8 +48,8 @@ export default {
name: 'Status',
fieldType: 'enumeration',
options: [
{ key: 'draft', name: 'Draft' },
{ key: 'published', name: 'Published' },
{ key: 'draft', label: 'Draft' },
{ key: 'published', label: 'Published' },
],
filterCustomQuery: StatusFieldFilterQuery,
sortCustomQuery: StatusFieldSortQuery,

View File

@@ -6,23 +6,23 @@ export default {
},
fields: {
name: {
label: 'Name',
name: 'Name',
column: 'name',
fieldType: 'text',
},
description: {
label: 'Description',
name: 'Description',
column: 'description',
fieldType: 'text',
},
count: {
label: 'Count',
name: 'Count',
column: 'count',
fieldType: 'number',
virtualColumn: true,
},
created_at: {
label: 'Created at',
name: 'Created at',
column: 'created_at',
columnType: 'date',
},

View File

@@ -6,43 +6,47 @@ export default {
},
fields: {
'date': {
label: 'Date',
name: 'Date',
column: 'date',
fieldType: 'date',
},
'journal_number': {
label: 'Journal number',
name: 'Journal number',
column: 'journal_number',
fieldType: 'text',
},
'reference': {
label: 'Reference No.',
name: 'Reference No.',
column: 'reference',
fieldType: 'text',
},
'journal_type': {
label: 'Journal type',
name: 'Journal type',
column: 'journal_type',
fieldType: 'text',
},
'amount': {
label: 'Amount',
name: 'Amount',
column: 'amount',
columnType: 'number',
fieldType: 'number',
},
'description': {
label: 'Description',
name: 'Description',
column: 'description',
fieldType: 'text',
},
'status': {
label: 'Status',
name: 'Status',
column: 'status',
fieldType: 'enumeration',
options: [
{ key: 'draft', label: 'Draft' },
{ key: 'published', label: 'published' }
],
sortCustomQuery: StatusFieldSortQuery,
},
'created_at': {
label: 'Created at',
name: 'Created at',
column: 'created_at',
fieldType: 'date',
},

View File

@@ -26,8 +26,8 @@ export default (Model) =>
* @param {string} key
* @returns
*/
public static getMeta(key: string) {
return get(this.meta, key);
public static getMeta(key?: string) {
return key ? get(this.meta, key): this.meta;
}
/**

View File

@@ -55,11 +55,11 @@ export default {
name: 'Status',
fieldType: 'enumeration',
options: [
{ name: 'Delivered', key: 'delivered' },
{ name: 'Rejected', key: 'rejected' },
{ name: 'Approved', key: 'approved' },
{ name: 'Delivered', key: 'delivered' },
{ name: 'Draft', key: 'draft' },
{ label: 'Delivered', key: 'delivered' },
{ label: 'Rejected', key: 'rejected' },
{ label: 'Approved', key: 'approved' },
{ label: 'Delivered', key: 'delivered' },
{ label: 'Draft', key: 'draft' },
],
filterCustomQuery: StatusFieldFilterQuery,
sortCustomQuery: StatusFieldSortQuery,

View File

@@ -64,15 +64,14 @@ export default {
},
status: {
name: 'Status',
columnable: true,
fieldType: 'enumeration',
options: [
{ key: 'draft', name: 'Draft' },
{ key: 'delivered', name: 'Delivered' },
{ key: 'unpaid', name: 'Unpaid' },
{ key: 'overdue', name: 'Overdue' },
{ key: 'partially-paid', name: 'Partially paid' },
{ key: 'paid', name: 'Paid' },
{ key: 'draft', label: 'Draft' },
{ key: 'delivered', label: 'Delivered' },
{ key: 'unpaid', label: 'Unpaid' },
{ key: 'overdue', label: 'Overdue' },
{ key: 'partially-paid', label: 'Partially paid' },
{ key: 'paid', label: 'Paid' },
],
filterCustomQuery: StatusFieldFilterQuery,
sortCustomQuery: StatusFieldSortQuery,
@@ -97,4 +96,4 @@ function StatusFieldFilterQuery(query, role) {
*/
function StatusFieldSortQuery(query, role) {
query.modify('sortByStatus', role.order);
}
}

View File

@@ -22,8 +22,8 @@ export default {
relationEntityKey: 'slug',
},
'customer': {
name: 'Customer',
column: 'customer_id',
label: 'Customer',
name: 'customer_id',
fieldType: 'relation',
relationType: 'enumeration',
@@ -67,8 +67,8 @@ export default {
name: 'Status',
fieldType: 'enumeration',
options: [
{ key: 'draft', name: 'Draft' },
{ key: 'closed', name: 'Closed' },
{ key: 'draft', label: 'Draft' },
{ key: 'closed', label: 'Closed' },
],
filterCustomQuery: StatusFieldFilterQuery,
sortCustomQuery: StatusFieldSortQuery,

View File

@@ -71,7 +71,8 @@ export default {
fieldType: 'text',
},
'status': {
label: 'Status',
name: 'Status',
type: 'enumeration',
options: [
{ key: 'overdue', label: 'Overdue' },
{ key: 'unpaid', label: 'Unpaid' },

View File

@@ -3,9 +3,6 @@ import { camelCase, upperFirst } from 'lodash';
import pluralize from 'pluralize';
import { buildFilter } from 'objection-filter';
import { IModel, IModelMeta } from 'interfaces';
import {
getModelFields,
} from 'lib/ViewRolesBuilder'
import TenancyService from 'services/Tenancy/TenancyService';
import { ServiceError } from 'exceptions';
@@ -20,62 +17,12 @@ export default class ResourceService {
/**
* Transform resource to model name.
* @param {string} resourceName
* @param {string} resourceName
*/
private resourceToModelName(resourceName: string): string {
return upperFirst(camelCase(pluralize.singular(resourceName)));
}
/**
* Retrieve model fields.
* @param {number} tenantId
* @param {IModel} Model
*/
private getModelFields(tenantId: number, Model: IModel) {
const { __ } = this.tenancy.i18n(tenantId);
const fields = getModelFields(Model);
return fields.map((field) => ({
label: __(field.label),
key: field.key,
dataType: field.columnType,
fieldType: field.fieldType,
...(field.options) ? {
options: field.options.map((option) => ({
...option, label: __(option.label),
})),
} : {},
...(field.optionsResource) ? {
optionsResource: field.optionsResource,
optionsKey: field.optionsKey,
optionsLabel: field.optionsLabel,
} : {},
}));
}
/**
* Should model be resource-able or throw service error.
* @param {IModel} model
*/
private shouldModelBeResourceable(model: IModel) {
if (!model.resourceable) {
throw new ServiceError(ERRORS.RESOURCE_MODEL_NOT_FOUND);
}
}
/**
* Retrieve resource fields from resource model name.
* @param {string} resourceName
*/
public getResourceFields(tenantId: number, modelName: string) {
const resourceModel = this.getResourceModel(tenantId, modelName);
this.shouldModelBeResourceable(resourceModel);
return this.getModelFields(tenantId, resourceModel);
}
/**
* Retrieve resource model object.
* @param {number} tenantId -
@@ -91,29 +38,18 @@ export default class ResourceService {
return Models[modelName];
}
/**
* Retrieve resource data from the storage based on the given query.
* @param {number} tenantId
* @param {string} modelName
*/
public async getResourceData(tenantId: number, modelName: string, filter: any) {
const resourceModel = this.getResourceModel(tenantId, modelName);
this.shouldModelBeResourceable(resourceModel);
return buildFilter(resourceModel).build(filter);
}
/**
* Retrieve the resource meta.
* @param {number} tenantId
* @param {string} modelName
* @param {number} tenantId
* @param {string} modelName
* @returns {IModelMeta}
*/
public getResourceMeta(tenantId: number, modelName: string): IModelMeta {
public getResourceMeta(
tenantId: number,
modelName: string,
metakey?: string
): IModelMeta {
const resourceModel = this.getResourceModel(tenantId, modelName);
const settings = resourceModel.meta();
return settings;
return resourceModel.getMeta(metakey);
}
}
}