Qone

下一代 Web 查询语言,使 javascript 支持 LINQ

Github: github.com/dntzhang/qo…

缘由

最近刚好修改了腾讯文档 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下面的脚本怎么转成 javascript 运行?

= IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 是 foo", "A2 不是 foo")
复制代码

公式或一些脚本语言的实现包含几个主要步骤:

scanner > lexer > parser > ast > code string
复制代码

得到 code string 之后可以动态运行,比如 js 里使用 eval ,eval 能保留上下文信息,缺点是执行代码包含编译器代码,eval 的安全性等。 得到 code string 之后也可直接使用生成的 code string 运行,缺点是依赖构建工具或者编辑器插件去动态替换源代码。

比如 wind 同时支持 JIT 和 AOT, qone 的思路和上面类似,但不完全相同, qone 的如下:

scanner > lexer > parser > ast > method(ast)
复制代码

这个后面写原理时候再细说。

总的来说,因为腾讯文档公式相关工作、早年的 kmdjs 开发 (uglify2) 和 .NET 开发,所以有了 qone 。

  • LINQ
  • qone 安装
  • qone 关键字与运算符
  • qone 方法注入
  • qone select 输出
  • qone orderby
  • qone groupby
  • qone 多数据源
  • qone 嵌套子数据源
  • qone limit 与分页查询
  • links

LINQ

LINQ (语言集成查询) 是 .NET Framework 3.5 版中引入的一项创新功能。在 Visual Studio 中,可以用 Visual Basic 或 C# 为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及可枚举的 Objects(即 LINQ to Objects)。

qone 是一款让 Web 前端工程师在 javascript 使用 .NET 平台下类似 LINQ 语法的前端库。qone 让 Web 前端工程师通过字符串的形式实现了 LINQ to Objects 的调用(下面统一叫做 qone to objects),Objects即 JSON 组成的 Array。举个简单的例子(qone 远比下面的例子强大):

var list = [{ name: 'qone', age: 1 },{ name: 'linq', age: 18 },{ name: 'dntzhang', age: 28 }
]var result = qone({ list }).query(`from n in list   where n.age > 18select n`)assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
复制代码

与 LINQ 一样,和 SQL 不同,qone 的 from 也在前面,为后面语句能够有智能提示,qone 是基于 string 的实时编译,不是 javasript 的原生语法,所以虽然 from 写在前面但不支持智能提示,但可以专门为 qone 写个编辑器插件去实现智能提示,所以 qone 语法设计上依然把 from 放在前面。

从根本上说,qone to objects 表示一种新的处理集合的方法。 采用旧方法,您必须编写指定如何从集合检索数据的复杂的 foreach 循环。 而采用 qone 方法,您只需编写描述要检索的内容的声明性代码。 另外,与传统的 foreach 循环相比,qone 查询具有三大优势:

  • 它们更简明、更易读,尤其在筛选多个条件时
  • 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能
  • 无需修改或只需做很小的修改即可将它们移植到其他数据源

通常,您要对数据执行的操作越复杂,就越能体会到 qone 相较于传统迭代技术的优势。

qone 安装

npm install qone
复制代码

qone 关键字与运算符

  • from
  • in
  • where
  • select
  • orderby
  • desc
  • asc
  • groupby
  • limit

其中 from 和 in 一起使用,orderby 和 desc 或者 asc 一起使用。

from 也可以把子属性作为 dataSource:

from n in data.list
复制代码

qone 支持下面三类运算符:

  • 括号:( )
  • 比较运算符: = , > , < , >= , <= , !=
  • 与或非: && , || , !

条件判断语句也支持 null, undefined, true, false。

通过上面各种组合,你可以写出很复杂的查询条件。比如:

qone({ list }).query(`from n in list   where !(n.age > 17 || n.age < 2) && n.name != 'dntzhang'select n
`)
复制代码

也支持 bool 类型的查询:

var list = [{ name: 'qone', age: 1, isBaby: true },{ name: 'linq', age: 18 },{ name: 'dntzhang', age: 28 }]var result = qone({ list }).query(`from a in list       where a.isBaby && n.name = 'qone'select a`)assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
复制代码

其中 isBaby 是 bool 类型,同样的写法: a.isBaby = true (等同于: a.isBaby) a.isBaby = false (等同于: !a.isBaby)

qone 方法注入

通过上面介绍发现 qone 不支持加减乘除位求模运算?怎么才能图灵完备?方法注入搞定一切!如下所示:

QUnit.test("Method test 8", function (assert) {var arr = [1, 2, 3, 4, 5]qone('square', function (num) {return num * num})qone('sqrt', function (num) {return Math.sqrt(num)})var result = qone({ arr }).query(`from n in arr   where  sqrt(n) >= 2 select { squareValue : square(n) }`)assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
})
复制代码

方法也是支持多参数传入,所以可以写出任意的查询条件。其中select, where, orderby, groupby 语句都支持方法注入。

qone select 输出

通过 select 可以输出各种格式和字段的数据:

QUnit.test("Select JSON test", function (assert) {var list = [{ name: 'qone', age: 1 },{ name: 'linq', age: 18 },{ name: 'dntzhang', age: 28 }]var result = qone({ list }).query(`from n in list   where n.age < 20select {n.age, n.name}`)assert.deepEqual(result, [{ "age": 1 , "name": "qone" },{ "age": 18, "name": "linq" }])})
复制代码

把所有场景列举一下:

  • select n 输出源 item
  • select n.name 输出一维表
  • select n.name, n.age 输出二维表
  • select { n.age, n.name } 缺省方式输出 JSON Array(key自动使用 age 和 name)
  • select { a: n.age, b: n.name } 指定 key 输出 JSON Array
  • select { a: methodName(n.age), b: n.name } 注入方法
  • select methodName(n.age), n.name 注入方法
  • select methodName(n.age, n.name, 1, true, 'abc') 注入方法并传递参数

qone orderby

var result = qone({ list }).query(`from n in list   where n.age > 0orderby n.age asc, n.name descselect n`)复制代码

如果没有标记 asc 或者 desc,使用默认排序 asc。

qone groupby

QUnit.test("Simple groupby test 1", function (assert) {var list = [{ name: 'qone', age: 1 },{ name: 'linq', age: 18 },{ name: 'dntzhang1', age: 28 },{ name: 'dntzhang2', age: 28 },{ name: 'dntzhang3', age: 29 }]var result = qone({ list }).query(`from n in list   where n.age > 18groupby n.age`)assert.deepEqual(result, [[{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],[{ "name": "dntzhang3", "age": 29 }]])})
复制代码

groupby 可以作为结束语句,不用跟着也不能跟着 select 语句,groupby 也可以支持方法注入。

qone 多数据源

QUnit.test("Multi datasource with props condition", function (assert) {var listA = [{ name: 'qone', age: 1 },{ name: 'linq', age: 18 },{ name: 'dntzhang', age: 28 }]var listB = [{ name: 'x', age: 11 },{ name: 'xx', age: 18 },{ name: 'xxx', age: 13 }]var result = qone({ listA, listB }).query(`from a in listA     from b in listB      where a.age = b.ageselect a, b`)assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
})
复制代码

多数据源会产生笛卡儿积。

qone 嵌套子数据源

QUnit.test("Multi deep from test ", function (assert) {var list = [{ name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },{ name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },{ name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]var result = qone({ list }).query(`from a in list   from c in a.colors   from d in c.xx  where d === 100select a.name, c,d`)assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
})
复制代码

也可以和自身的数据源会产生笛卡儿积。

qone limit 与分页查询

通过 limit 可以应付最常见的两种查询场景 - top N 和 分页。

查询top3:

QUnit.test("Limit top 3", function (assert) {var list = [{ name: 'dntzhang1', age: 1 },{ name: 'dntzhang2', age: 2 },{ name: 'dntzhang3', age: 3 },{ name: 'dntzhang4', age: 4 },{ name: 'dntzhang5', age: 5 },{ name: 'dntzhang6', age: 6 },{ name: 'dntzhang7', age: 7 },{ name: 'dntzhang8', age: 8 },{ name: 'dntzhang9', age: 9 },{ name: 'dntzhang10', age: 10 }]var pageIndex = 1,pageSize = 4var result = qone({ list }).query(`from n in list   select nlimit 0, 3`)assert.deepEqual(result, [{ name: 'dntzhang1', age: 1 },{ name: 'dntzhang2', age: 2 },{ name: 'dntzhang3', age: 3 }])})
复制代码

分页查询:

QUnit.test("Limit one page test", function (assert) {var list = [{ name: 'dntzhang1', age: 1 },{ name: 'dntzhang2', age: 2 },{ name: 'dntzhang3', age: 3 },{ name: 'dntzhang4', age: 4 },{ name: 'dntzhang5', age: 5 },{ name: 'dntzhang6', age: 6 },{ name: 'dntzhang7', age: 7 },{ name: 'dntzhang8', age: 8 },{ name: 'dntzhang9', age: 9 },{ name: 'dntzhang10', age: 10 }]var pageIndex = 1,pageSize = 4var result = qone({ list }).query(`from n in list   where n.age > 0select nlimit ${pageIndex * pageSize}, ${pageSize}`)assert.deepEqual(result, [{ name: 'dntzhang5', age: 5 },{ name: 'dntzhang6', age: 6 },{ name: 'dntzhang7', age: 7 },{ name: 'dntzhang8', age: 8 }])})
复制代码

star & fork & pr & repl & follow me

  • github.com/dntzhang/qo…
  • dntzhang.github.io/qone
  • github.com/dntzhang

Qone 正式开源,使 javascript 支持 .NET LINQ相关推荐

  1. 【开源】Qone 正式发布,使 javascript 支持 .NET LINQ

    Qone 下一代 Web 查询语言,使 javascript 支持 LINQ Github: https://github.com/dntzhang/qone 缘由 最近刚好修改了腾讯文档 Excel ...

  2. mac webpack 版本_晓前端周刊 第48期:EMP面向未来微前端方案正式开源了!玩转 webpack,使你的打包速度提升 90%;...

    业界动态 苹果最大杀招:iPhone App 已能在电脑运行 近日网友反馈,苹果 App Store 中大量应用在兼容性一栏中显示:已支持运行 macOS 11(及以上版本)的 Mac 电脑.这意味着 ...

  3. 华为明年手机全面支持鸿蒙系统,华为鸿蒙系统正式开源,余承东:明年华为手机全面支持鸿蒙系统...

    钱江晚报·小时新闻记者 徐健 张云山 华为开发者大会2020今天在东莞松山湖拉开帷幕.在大会的主题演讲中,华为带来了HarmonyOS 2.0.EMUI 11.HMS.HUAWEI HiLink.HU ...

  4. 五福背后的 Web 3D 引擎 Oasis Engine 正式开源

    简介: Oasis 从开源走向新的起点,用 3D 化的交互和表达让世界变得更美好. 相信大家已经体验了今年支付宝五福的活动,无论是今年的五福首页还是打年兽游戏都是由蚂蚁互动图形引擎(代号:Oasis ...

  5. 微软宣布正式开源 Azure IoT Edge 边缘计算服务

    微软宣布,去年年底公开预览的 Azure IoT Edge 边缘计算服务已进入官方版,并通过 GitHub 将其开源. Azure IoT Edge 主要将基于云的分析和定制的业务逻辑转移到边缘设备, ...

  6. 本人制作的股票技术分析软件正式开源(.net wpf)

    为什么80%的码农都做不了架构师?>>> 本人制作的股票技术分析软件正式开源 该软件以股票数据为核心,尤其以按日数据为主,采用图表方式可视化股票数据 ,为用户提供简单的股票选择可视化 ...

  7. Netflix正式开源其API网关Zuul 2--转

    微信公众号:聊聊架构 5 月 21 日,Netflix 在其官方博客上宣布正式开源微服务网关组件 Zuul 2.Netflix 公司是微服务界的楷模,他们有大规模生产级微服务的成功应用案例,也开源了相 ...

  8. 腾讯 AI Lab 正式开源PocketFlow自动化深度学习模型压缩与加速框架

    11月1日,腾讯AI Lab在南京举办的腾讯全球合作伙伴论坛上宣布正式开源"PocketFlow"项目, 该项目是一个自动化深度学习模型压缩与加速框架,整合多种模型压缩与加速算法并 ...

  9. 阿里巴巴云原生混部系统 Koordinator 正式开源

    简介: 脱胎于阿里巴巴内部,经过多年双 11 打磨,每年为公司节省数十亿的混部系统 Koordinator 今天宣布正式开源.通过开源,我们希望将更好的混部能力.调度能力开放到整个行业,帮助企业客户改 ...

最新文章

  1. hdu4081 最小树+DFS或者次小树的变形
  2. 如何解决win8系统下卸载软件出现错误代码为2502和2503的问题
  3. python数据分析架构_Python数据分析
  4. python里it n_Python3 round(x [,n]) 函数
  5. 【华为云技术分享】三大前端技术(React,Vue,Angular)探密(上)
  6. BZOJ 1779. [Usaco2010 Hol]Cowwar 奶牛战争
  7. 分享一些做课题调查的方法
  8. 感知机-收敛性证明及代码实现
  9. 前端vue生成二维码
  10. 伦敦时间现在几点_英国伦敦现在时间是几点
  11. 解决方案:Win C++ mingw编译器出现 不支持的16位程序问题
  12. Android面试知识点复习,那些不为人知的秘密
  13. 八泉峡明星旅游目的地系列推介会即将举行 蒋大为将现身助阵
  14. win10右键一直转圈_惠普产品拆机图文哪里找?桌面点右键延迟咋办?内存怎么少了?...
  15. 神经科学探索脑第二十二章
  16. @Transactional的七种事务传播行为
  17. eclipse因jdk打不开解决
  18. 软件项目该如何接?(转自速用)
  19. html css3 纸张,CSS3 设计巧妙的纸张褶起动效
  20. 一个ZFS开发者眼中的苹果最新文件存储系统APFS

热门文章

  1. 数据结构与算法(Java版) | 数据结构与算法的重要性
  2. J2EE开发技术概述
  3. 重重封锁,让你一条数据都拿不到《死磕MySQL系列 十三》
  4. 门窗计算机公式,13种铝合金门窗下料尺寸计算公式
  5. RabbitMQ之集群搭建管理
  6. Ubuntu非正常断电 进入紧急模式处理办法
  7. 割接方案,迁移方案英文怎么说
  8. 百度贴吧csrf让全吧吧友在自己都不知情的情况下帮你投诉指定贴吧吧主的bug
  9. C++STL库中不可或缺的部分—string(模拟实现)
  10. SQLMap 从入门到入狱详细指南