将请求转换为友好的自动查询

Transform Request to Autoquery friendly

我们正在使用内置 paging/sorting/filtering 的第 3 方网格 (telerik kendo)。它会在进行 GET 调用时以特定方式发送请求,我正在尝试确定是否有办法将这些请求转换为 AutoQuery 友好请求。

查询字符串参数

排序模式:

sort[{0}][field] and sort[{0}][dir]

过滤:

filter[filters][{0}][field]
filter[filters][{0}][operator]
filter[filters][{0}][value]

所以在查询字符串中填充的是:

filter[filters][0][field]
filter[filters][0][operator]
filter[filters][0][value]

需要翻译成。

FieldName=1  //      filter[filters][0][field]+filter[filters][0][operator]+filter[filters][0][value] in a nutshell (not exactly true)

我应该通过删除过滤器(或只添加我需要的过滤器)来操作插件中的查询字符串对象吗?这里有更好的选择吗?

我不确定在 kendo 方面是否有一种干净的方法来做到这一点。

我会解释下我走的两条路线,希望看到更好的答案。

首先,我尝试修改请求过滤器中的查询字符串,但不能。我最终不得不通过获取参数并在调用 AutoQuery.Execute 之前修改它们来手动 运行 自动查询。像这样:

var requestparams = Request.ToAutoQueryParams();
var q = AutoQueryDb.CreateQuery(requestobject, requestparams);
AutoQueryDb.Execute(requestobject, q);

我希望有一种更全球化的方式来做到这一点。扩展方法只是遍历所有查询字符串参数并添加我需要的参数。

完成上述工作后,我对结果不是很满意,所以我研究了不同的做法,结果如下:

将 Kendo 网格过滤器操作注册到其等效的服务堆栈自动查询操作:

 var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer=true };
        aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
        aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");

接下来,在网格的读取操作中,我们需要重新格式化查询字符串:

read: {
                                url: "/api/stuff?format=json&isGrid=true",
                                data: function (options) {
                                    if (options.sort && options.sort.length > 0) {
                                        options.OrderBy = (options.sort[0].dir == "desc" ? "-" : "") + options.sort[0].field;
                                    }
                                    if (options.filter && options.filter.filters.length > 0) {
                                        for (var i = 0; i < options.filter.filters.length; i++) {
                                            var f = options.filter.filters[i];
                                            console.log(f);
                                            options[f.field + f.operator] = f.value;
                                        }
                                    }

                                }

现在,网格将以自动查询友好的方式发送操作。

我创建了一个 AutoQueryDataSource ts class,您可能会觉得有用,也可能不会。

它的用法是:

this.gridDataSource = AutoQueryKendoDataSource.getDefaultInstance<dtos.QueryDbSubclass, dtos.ListDefinition>('/api/autoQueryRoute', { orderByDesc: 'createdOn' });


export default class AutoQueryKendoDataSource<queryT extends dtos.QueryDb_1<T>, T> extends kendo.data.DataSource {
    private constructor(options: kendo.data.DataSourceOptions = {}, public route?: string, public request?: queryT) {
        super(options)
    }

    defer: ng.IDeferred<any>;
    static exportToExcel(columns: kendo.ui.GridColumn[], dataSource: kendo.data.DataSource, filename: string) {
        let rows = [{ cells: columns.map(d => { return { value: d.field }; }) }];
        dataSource.fetch(function () {
            var data = this.data();
            for (var i = 0; i < data.length; i++) {
                //push single row for every record
                rows.push({
                    cells: _.map(columns, d => { return { value: data[i][d.field] } })
                })
            }
            var workbook = new kendo.ooxml.Workbook({
                sheets: [
                    {
                        columns: _.map(columns, d => { return { autoWidth: true } }),
                        // Title of the sheet
                        title: filename,
                        // Rows of the sheet
                        rows: rows
                    }
                ]
            });
            //save the file as Excel file with extension xlsx
            kendo.saveAs({ dataURI: workbook.toDataURL(), fileName: filename });
        })
    }

    static getDefaultInstance<queryT extends dtos.QueryDb_1<T>, T>(route: string, request: queryT, $q?: ng.IQService, model?: any) {
        let sortInfo: {
            orderBy?: string,
            orderByDesc?: string,
            skip?: number
        } = {
        };

        let opts = {
            transport: {
                read: {
                    url: route,
                    dataType: 'json',
                    data: request
                },
                parameterMap: (data, type) => {
                    if (type == 'read') {
                        if (data.sort) {
                            data.sort.forEach((s: any) => {
                                if (s.field.indexOf('.') > -1) {
                                    var arr = _.split(s.field, '.')
                                    s.field = arr[arr.length - 1];
                                }

                            })
                        }//for autoquery to work, need only field names not entity names.

                        sortInfo = {
                            orderByDesc: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'desc'), 'field'), ','),
                            orderBy: _.join(_.map(_.filter(data.sort, (s: any) => s.dir == 'asc'), 'field'), ','),
                            skip: 0
                        }

                        if (data.page)
                            sortInfo.skip = (data.page - 1) * data.pageSize,
                                _.extend(data, request);
                        //override sorting if done via grid
                        if (sortInfo.orderByDesc) {
                            (<any>data).orderByDesc = sortInfo.orderByDesc;
                            (<any>data).orderBy = null;
                        }
                        if (sortInfo.orderBy) {
                            (<any>data).orderBy = sortInfo.orderBy;
                            (<any>data).orderByDesc = null;
                        }
                        (<any>data).skip = sortInfo.skip;

                        return data;
                    }
                    return data;
                },
            },
            requestStart: (e: kendo.data.DataSourceRequestStartEvent) => {
                let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;

                if ($q)
                    ds.defer = $q.defer();
            },
            requestEnd: (e: kendo.data.DataSourceRequestEndEvent) => {
                new DatesToStringsService().convert(e.response);
                let ds = <AutoQueryKendoDataSource<queryT, T>>e.sender;

                if (ds.defer)
                    ds.defer.resolve();
            },
            schema: {
                data: (response: dtos.QueryResponse<T>) => {
                    return response.results;
                },
                type: 'json',
                total: 'total',
                model: model
            },
            pageSize: request.take || 40,
            page: 1,
            serverPaging: true,
            serverSorting: true
        }

        let ds = new AutoQueryKendoDataSource<queryT, T>(opts, route, request);
        return ds;
    }
}