摘要:下一代查詢語言,使支持緣由最近剛好修改了騰訊文檔表格公式的一些,主要是修改公式的。總的來說,因為騰訊文檔公式相關(guān)工作早年的開發(fā)和開發(fā),所以有了。讓前端工程師通過字符串的形式實現(xiàn)了的調(diào)用下面統(tǒng)一叫做,即組成的。多數(shù)據(jù)源多數(shù)據(jù)源會產(chǎn)生笛卡兒積。
Qone
下一代 Web 查詢語言,使 javascript 支持 LINQ
Github: https://github.com/dntzhang/qone
緣由最近剛好修改了騰訊文檔 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下面的腳本怎么轉(zhuǎn)成 javascript 運行?
= IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 是 foo", "A2 不是 foo")
公式或一些腳本語言的實現(xiàn)包含幾個主要步驟:
scanner > lexer > parser > ast > code string
得到 code string 之后可以動態(tài)運行,比如 js 里使用 eval ,eval 能保留上下文信息,缺點是執(zhí)行代碼包含編譯器代碼,eval 的安全性等。
得到 code string 之后也可直接使用生成的 code string 運行,缺點是依賴構(gòu)建工具或者編輯器插件去動態(tài)替換源代碼。
比如 wind 同時支持 JIT 和 AOT, qone 的思路和上面類似,但不完全相同, qone 的如下:
scanner > lexer > parser > ast > method(ast)
這個后面寫原理時候再細(xì)說。
總的來說,因為騰訊文檔公式相關(guān)工作、早年的 kmdjs 開發(fā) (uglify2) 和 .NET 開發(fā),所以有了 qone 。
LINQ
qone 安裝
qone 關(guān)鍵字與運算符
qone 方法注入
qone select 輸出
qone orderby
qone groupby
qone 多數(shù)據(jù)源
qone 嵌套子數(shù)據(jù)源
qone limit 與分頁查詢
links
LINQLINQ (語言集成查詢) 是 .NET Framework 3.5 版中引入的一項創(chuàng)新功能。在 Visual Studio 中,可以用 Visual Basic 或 C# 為以下數(shù)據(jù)源編寫 LINQ 查詢:SQL Server 數(shù)據(jù)庫、XML 文檔、ADO.NET 數(shù)據(jù)集,以及可枚舉的 Objects(即 LINQ to Objects)。
qone 是一款讓 Web 前端工程師在 javascript 使用 .NET 平臺下類似 LINQ 語法的前端庫。qone 讓 Web 前端工程師通過字符串的形式實現(xiàn)了 LINQ to Objects 的調(diào)用(下面統(tǒng)一叫做 qone to objects),Objects即 JSON 組成的 Array。舉個簡單的例子(qone 遠(yuǎn)比下面的例子強(qiáng)大):
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 > 18 select n `) assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
與 LINQ 一樣,和 SQL 不同,qone 的 from 也在前面,為后面語句能夠有智能提示,qone 是基于 string 的實時編譯,不是 javasript 的原生語法,所以雖然 from 寫在前面但不支持智能提示,但可以專門為 qone 寫個編輯器插件去實現(xiàn)智能提示,所以 qone 語法設(shè)計上依然把 from 放在前面。
從根本上說,qone to objects 表示一種新的處理集合的方法。 采用舊方法,您必須編寫指定如何從集合檢索數(shù)據(jù)的復(fù)雜的 foreach 循環(huán)。 而采用 qone 方法,您只需編寫描述要檢索的內(nèi)容的聲明性代碼。
另外,與傳統(tǒng)的 foreach 循環(huán)相比,qone 查詢具有三大優(yōu)勢:
它們更簡明、更易讀,尤其在篩選多個條件時
它們使用最少的應(yīng)用程序代碼提供強(qiáng)大的篩選、排序和分組功能
無需修改或只需做很小的修改即可將它們移植到其他數(shù)據(jù)源
通常,您要對數(shù)據(jù)執(zhí)行的操作越復(fù)雜,就越能體會到 qone 相較于傳統(tǒng)迭代技術(shù)的優(yōu)勢。
qone 安裝npm install qoneqone 關(guān)鍵字與運算符
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。
通過上面各種組合,你可以寫出很復(fù)雜的查詢條件。比如:
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)
通過上面介紹發(fā)現(xiàn) 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 }]) })
方法也是支持多參數(shù)傳入,所以可以寫出任意的查詢條件。其中select, where, orderby, groupby 語句都支持方法注入。
qone select 輸出通過 select 可以輸出各種格式和字段的數(shù)據(jù):
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 < 20 select {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") 注入方法并傳遞參數(shù)
qone orderbyvar result = qone({ list }).query(` from n in list where n.age > 0 orderby n.age asc, n.name desc select n `)
如果沒有標(biāo)記 asc 或者 desc,使用默認(rèn)排序 asc。
qone groupbyQUnit.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 > 18 groupby n.age `) assert.deepEqual(result, [ [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }], [{ "name": "dntzhang3", "age": 29 }]]) })
groupby 可以作為結(jié)束語句,不用跟著也不能跟著 select 語句,groupby 也可以支持方法注入。
qone 多數(shù)據(jù)源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.age select a, b `) assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]]) })
多數(shù)據(jù)源會產(chǎn)生笛卡兒積。
qone 嵌套子數(shù)據(jù)源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 === 100 select a.name, c,d `) assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]]) })
也可以和自身的數(shù)據(jù)源會產(chǎn)生笛卡兒積。
qone limit 與分頁查詢通過 limit 可以應(yīng)付最常見的兩種查詢場景 - 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 = 4 var result = qone({ list }).query(` from n in list select n limit 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 = 4 var result = qone({ list }).query(` from n in list where n.age > 0 select n limit ${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
https://github.com/dntzhang/qone
https://dntzhang.github.io/qone
https://github.com/dntzhang
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/94580.html
閱讀 2652·2021-09-09 09:33
閱讀 2810·2019-08-30 15:54
閱讀 2867·2019-08-30 14:21
閱讀 2356·2019-08-29 17:15
閱讀 3580·2019-08-29 16:13
閱讀 2759·2019-08-29 14:21
閱讀 3422·2019-08-26 13:25
閱讀 2028·2019-08-26 12:14