如何从 SQL where 子句创建一个 JavaScript 函数,以将其作为谓词传递给 JavaScript 数组的过滤函数?

Posted

技术标签:

【中文标题】如何从 SQL where 子句创建一个 JavaScript 函数,以将其作为谓词传递给 JavaScript 数组的过滤函数?【英文标题】:How can I create a JavaScript function from SQL where clause to pass it into filter function of JavaScript arrays as a predicate? 【发布时间】:2013-12-05 15:04:14 【问题描述】:

场景:

我有一个基于 javascript 的应用程序,它使用 web sql 数据库来存储其数据

我开发了一个自定义实体集。

它有一个过滤方法,可以接受包含sql查询的字符串。

例如:People.filter("Name = 'Test' and ...")

我的实体集的行为有两种模式,InMemoryNonInMemory

InMemory: filter 方法会过滤内存中的源数组,无需往返db。

NonInMemory:过滤器方法将使用新过滤器再次从数据库中读取源代码。

为了更轻松的开发,我想让开发人员对这些行为的差异透明化。

我想让我的过滤器方法在两种模式(InMemoryNonInMemory)上都可以使用相同的代码。

我有数千个这样的过滤器,它们在 .net 和 sql lite 中运行良好。

我想尽可能简单地将它们迁移到 JavaScript 和 web sql。

我的问题:

是否有任何 JavaScript 库可以处理这种情况?

哪个接受 Sql 查询并为我创建一个 JavaScript 函数作为谓词?

谢谢

【问题讨论】:

webSQL 本身会将您的字符串作为 sql 执行,以对您需要的结果集进行切片和切块。 @dandavis 谢谢,webSQL 确实做到了,但我的问题是我想执行相同的 sql 谓词“InMemory”。在 .NET 的 Dynamic Linq 之类的东西中,我想创建一个 JavaScript 函数作为执行该 InMemory 的谓词,而无需往返数据库。有什么想法吗? 有一些纯js sql项目,但他们都是业余的恕我直言。 linq 库没问题。 taffyDB 是 sql-ish。根据查询,许多 sql 子句可以通过可重复使用的 [].filter/[].map 函数进行编码。 @dandavis 我要测试 linq.js 并在这里报告我的测试结果。谢谢 【参考方案1】:

我实际上正在开发一个基于 sql 的 JavaScript 项目,该项目使用生成的函数作为 where 子句。其中一部分是将SQL语法差异转换为可行的JS(AND>&&等),另一部分是为子句提供SQL功能。项目不完整,没有100%甚至80%的目标兼容性,只是为了让最有用的 sql 特性和语法在 javascript 中工作。下面的 where-function 创建例程不是解析器或复杂的 AST 构建器,只是一个半天真的但快速且足够的字符串转换器。

它现在支持大量的 where-ish SQL 并且应该很容易扩展你自己;这里没有太多的黑魔法。

生成的函数非常适合 filter() 对象数组。

这里是项目相关部分的一个端口,相当大,where-clause builder:

// cache RegExps pseudo-globally for much better perf in query routine in webkit:
var rxOr = /\sOR\s/g,
    rxAnd = /\sAND\s/g,
    rxIn = /\sIN\(([\w\.\,\s]+)\)/g,
    rxSep = /\s*\,\s*/,
    rxDoubleEqual = /([^=])=([^=])/g,
    asRx = /\s+AS\s+/,
    eqRx = /(\w+)=/;
var fCache = ; //

var SQLREPS = [
    [/([^=])=([^=])/g, "$1==$2"],
    [/\sAND\s/g, ") && ("],
    [/\sOR\s/g, ") || ("],
    [/\bUCASE\(/g, " ''.toUpperCase.call("],
    [/\bLCASE\(/g, " ''.toLowerCase.call("],
    [/\bUPPER\(/g, " ''.toUpperCase.call("],
    [/\bLOWER\(/g, " ''.toLowerCase.call("],
    [/\bINSTR\(/g, " 1+''.indexOf.call("],
    [/\bCONCAT\(/g, " ''.concat("],
    [/\bLTRIM\(/g, " ''.trimLeft.call("],
    [/\bRTRIM\(/g, " ''.trimRight.call("],
    [/\bTRIM\(/g, " ''.trim.call("],
    [/\bQUOTE\(/g, " JSON.stringify("],
    [/\bSPACE\(/g, " ' '.repeat("],
    [/\bREPLACE\(/g, " (function(s,n,r)return s.split(n).join('r');)("],
    [/\bRPAD\(/g, " (function(s,n,p)return (s+p.repeat(n)).slice(0,n))("],
    [/\bASCII\(/g, " ''.charCodeAt.call("],
    [/\bBIN\(/g, " ''.charCodeAt.call("],
    [/\bLENGTH\(/g, " [].push.call("],
    [/\bSUBSTRING_INDEX\(/g, "(function(s,n,p)s=s.split(n);s=p>0?s.slice(0,p):s.slice(p);return s.join(n);)("],
    [/\bSUBSTRING\(/g, '(function(a,b,c)return b=[b>0?b-1:b],"".substr.apply(a,arguments.length==3?b.concat(c):b))('],
    [/\bSUBSTR\(/g, '(function(a,b,c)return b=[b>0?b-1:b],"".substr.apply(a,arguments.length==3?b.concat(c):b))('],
    [/\bMID\(/g, '(function(a,b,c)return b=[b>0?b-1:b],"".substr.apply(a,arguments.length==3?b.concat(c):b))('],
    [/\bLOCATE\(/g, " (function(t,s,n)return 1+s.indexOf(t,n))("],
    [/\bPOSITION\(/g, " (function(t,s,n)return 1+s.indexOf(t,n))("],
    [/\bFIND_IN_SET\(/g, "(function(s,l)return l.split(',').indexOf(s)+1)("],
    [/\bREVERSE\(/g, " (function(s)return s.split('').reverse().join('');)("],
    [/\bLEFT\(/g, "(function(s,n)return s.slice(0,n))("],
    [/ NOT /g, " ! "]
];



function rewrite(s) 

    var os = s;

    SQLREPS.forEach(function(a) 
        s = s.replace(a[0], a[1]);
    );

    s = s.replace(rxIn, function repIn(j, a) 
        return " in  " + a.split(rxSep).map(function mapIn(a) 
            return JSON.stringify(a)
        ).join(":1,") + ":1 ";
        return a;
    );

    return s;


function Function2(a, b, blnNoRewrite) 
    var c;
    if (!b.match(/return/)) 
        b = "return " + b;
    
    if (c = fCache[a + b]) 
        return c;
    
    return fCache[a + b] = Function(a, blnNoRewrite ? b : rewrite(b));



function sql(term) 
    return Function2("me,index,all", "return (" + rewrite(term) + ");");





//example strings and resulting functions:
sql(" UPPER(  me.gender  ) =='F' "); // function anonymous(me,index,all)return(''.toUpperCase.call(me.gender)=='F');

sql(" me.gender IN(M,F,O)"); //  function anonymous(me,index,all)return(me.gender in"M":1,"F":1,"O":1);

sql("(me.name> 'j' AND me.age > 50) &&  NOT me.inActive "); // function anonymous(me,index,all)return((me.name>'j')&&(me.age>50)&&!me.inActive);

大多数 js sql 库在 WHERE 功能上都有些吝啬,并且难以扩展,希望您和其他人可以从中获得一些使用或启发。作者认为它是公共领域,我。

【讨论】:

你的回答对我来说太有用了。非常感谢。但是我可以在我自己的应用程序中使用您的代码吗?如果我想对此进行任何更改,有什么方法可以为您自己的项目做出贡献吗?关于 随意对代码做任何你想做的事,我不介意分享。可悲的是,我还没有它在回购或任何方便的方式来关联更新,但如果你让它通电,我想看看;编辑答案,在此处回复链接或小提琴或给我发送电子邮件或其他内容。【参考方案2】:

似乎 OP 只想使用 SQL where 子句 query 一个 JavaScript 对象数组,无论他是否获得过滤功能。

AlaSQL 正是这样做的。但是,它 can be too big 用于您的应用程序包。

软件包的维护者还注意到(截至 2019 年 12 月):

AlaSQL 项目非常年轻,仍处于积极开发阶段,因此可能存在错误。

【讨论】:

以上是关于如何从 SQL where 子句创建一个 JavaScript 函数,以将其作为谓词传递给 JavaScript 数组的过滤函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用数千个 WHERE 子句优化 SQL 查询

如何在sql中创建动态where子句?

从雪花sql中的where子句中删除单引号

如何将字符串变量传递给动态sql中的where子句

关于sql语句添加where条件问题,用java语句

如果 where 子句已经修复,如何加快 spark sql 过滤器查询?