建立在JavaScript LINQ式查询API [英] Building a LINQ-like query API in JavaScript

查看:141
本文介绍了建立在JavaScript LINQ式查询API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个JavaScript类,它的工作原理是C#的的IQueryable< T> 接口,以实现对远程数据源很好地格式化的查询。换句话说,我希望能够写入以下内容(使用ES6箭头语法):

I'd like to write a JavaScript class that works like C#'s IQueryable<T> interface to enable nicely-formatted queries against a remote data source. In other words, I'd like to be able to write the following (using ES6 arrow syntax):

datasource.query(Sandwich)
    .where(s => s.bread.type == 'rye')
    .orderBy(s => s.ketchup.amount)
    .take(5)
    .select(s => { 'name': s.name });

和把它转换成类似

SELECT s.name AS name
FROM sandwich s
JOIN bread b ON b.sandwich_id = s.id
JOIN ketchup k on k.sandwich_id = s.id
WHERE b.type = 'rye'
ORDER BY k.amount
LIMIT 5;



与SQL查询(或任何查询语言时)被实际发送到服务器。 (做在客户端过滤是不可行的,因为服务器可能会返回大量数据的。)

with the SQL query (or whatever query language is used) being actually sent to the server. (Doing the filtering on the client side is not feasible because the server might return tons of data.)

在C#中,这个功能是由表达式类,它可以让你从一个lambda函数构造一个表达式树。但JavaScript有没有相应的,据我所知。我原来的计划是 f.toString()喂Esprima的解析器函数˚F作为参数传递给选择()在哪里()等,并使用表达式树。这种方法只要伟大工程的表达式仅涉及文字,但是当你尝试类似

In C#, this functionality is supported by the Expression class, which lets you construct an expression tree from a lambda function. But JavaScript has no equivalent, as far as I know. My original plan was to feed f.toString() to Esprima's parser for the function f passed as the argument to select(), where(), etc. and use that expression tree. This approach works great as long as the expressions refer only to literals, but when you try something like

var breadType = 'rye';

datasource.query(Sandwich)
    .where(s => s.bread.type == breadType)
...

失败,因为你有一个令牌breadType,你不能用一个值替换。据我所知,JavaScript有没有自查的功能关闭,并得到breadType的事实外部后的值。

it fails, because you'll have a token breadType that you can't replace with a value. As far as I can tell, JavaScript has no way to introspect the function closure and get the value of breadType after the fact externally.

我的下一个想法是,既然Esprima会给我一列记号,我可以修改就地东西函数体像

My next thought was that since Esprima will give me a list of tokens, I could modify the function body in-place to something like

return {
    'breadType': breadType
};



然后调用它,采取的事实,即使的 I 的优势不能访问封闭,函数本身即可。但是,就地函数的代码修改也似乎是不可能的。

and then call it, taking advantage of the fact that even if I can't access the closure, the function itself can. But modification of a function's code in-place also seems to be impossible.

这不会要求Esprima将是一个哨兵对象作为参数传递给另一种方法内部函数˚F并覆盖其比较运算,这是多么的SQLAlchemy的过滤器()在Python工作。但是Python提供运算符重载和JavaScript没有,所以这也将失败。

Another approach that would not require Esprima would be to pass in a sentinel object as the argument to the inner function f and override its comparison operators, which is how SQLAlchemy's filter() works in Python. But Python provides operator overloading and JavaScript does not, so this also fails.

这给我留下了两个劣解。一个是做这样的事情:

This leaves me with two inferior solutions. One is to do something like this:

var breadType = 'rye';

datasource.query(Sandwich)
    .where(s => s.bread.type == breadType)
    .forValues(() => {
        'breadType': breadType
    });

在换句话说,我可能会迫使调用者提供手动关闭背景。不过这是相当跛脚

In other words, I could force the caller to provide the closure context manually. But this is pretty lame.

另一种方法是做定点对象的事情,但对于功能,而不是运营商因为运营商不能重载:

Another approach is to do the sentinel object thing but with functions instead of operators since operators can't be overloaded:

var breadType = 'rye';

datasource.query(Sandwich)
    .where(s => s.bread.type.equals(breadType));



ES6的代理对象将让这个简单实现,但它仍然没有与普通运营商的版本一样好。

ES6's Proxy objects will make this simple to implement, but it's still not as good as the version with regular operators.

很抱歉的长期职位。我最终的问题是的是否有可能在第一代码块所示的理想语法来实现这一点,如果是这样,怎么办呢。谢谢!

Sorry for the long post. My ultimate question is whether it's possible to achieve this with the ideal syntax shown in the first code block and, if so, how to do it. Thanks!

推荐答案

没有,这是为你介绍的原因的确是不可能的。如果你想支持通过任意关闭作为参数,那么你唯一的选择是执行的功能。你无法将它们转换为SQL语句,在一定程度上这将永远不管你的文件有多少静态代码分析执行失败。

No, this is indeed impossible for the reasons you outlined. If you want to support passing arbitrary closures as arguments, then your only choice is to execute the functions. You cannot transform them to SQL statements, at some degree this will always fail regardless how many static code analysis you perform on the files.

我想你最好的选择这里有模板文字,在那里你可以有类似

I guess your best bet here are template literals, where you could have something like

var breadType = 'rye';
datasource.query(Sandwich, `
    .where(s => s.bread.type == ${breadType})
    .orderBy(s => s.ketchup.amount)
    .take(5)
    .select(s => { 'name': s.name })
`)

,这样你可以保持你的语法,只要你想,但必须明确地提供所有的外部变量。

so that you can keep your syntax as you want, but will have to supply all external variables explicitly.

这篇关于建立在JavaScript LINQ式查询API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆