1. 程式人生 > >【開源】Qone 正式釋出,使 javascript 支援 .NET LINQ

【開源】Qone 正式釋出,使 javascript 支援 .NET LINQ

Qone

下一代 Web 查詢語言,使 javascript 支援 LINQ

緣由

最近剛好修改了騰訊文件 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

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 > 18
            select 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 < 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') 注入方法並傳遞引數

qone orderby

var result = qone({ list }).query(`
                from n in list   
                where n.age > 0
                orderby n.age asc, n.name desc
                select 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 > 18
                groupby 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.age
            select 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 === 100
            select 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 = 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

相關推薦

開源Qone 正式釋出使 javascript 支援 .NET LINQ

Qone 下一代 Web 查詢語言,使 javascript 支援 LINQ 緣由 最近剛好修改了騰訊文件 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下面的指令碼怎麼轉成 javascript 執行? = IF(SUM(J6:J7) + SUM(J6:J7) > 10,

開源Skatch 正式釋出

極速渲染抽象派草圖 DEMO 簡介 Skatch 這個詞由 sketch wechart abstract cax 混合而成的一個新詞,代表了cax wechart 抽象藝術派派草圖渲染器。說得直白一點就是npm 上 sketch 被 tj 佔了,只能強行加上賦予某些意義合成 skatch 這

開源Westore Cloud 釋出- 沒後端沒SQL沒DBA只需 javascript 開發雲端小程式

Westore Cloud - 隱形雲,NoBackEnd,NoSql,HiddenDB 好的設計便是感覺不到設計的存在 開發小程式,但是:沒有後端!沒有運維!沒有 DBA!沒有域名!沒有證書!沒有錢!沒有精力! 沒關係,會 javascript 就可以,Westore Cloud 帶你起飛~~ Gith

官宣WijmoJS 2018 v3 正式釋出全面支援Angular7

WijmoJS(前端開發工具包)2018年度第三個大版本已經正式釋出,本次更新除了全面支援Angular7之外,還允許使用者使用Web Workers在前端更高效地匯出PDF、智慧的分組表頭屬性、全新的Ribbon主題示例以及OLAP功能增強。 本次主要更新特性有: WijmoJS 全面支援

前端開發工具WijmoJS 2018 v3 正式釋出全面支援Angular7

WijmoJS(前端開發工具包)2018年度第三個大版本已經正式釋出,本次更新除了全面支援Angular7之外,還允許使用者使用Web Workers在前端更高效地匯出PDF、智慧的分組表頭屬性、全新的Ribbon主題示例以及OLAP功能增強。 ​ 本次主要更新特性有: WijmoJS 全面支

開源騰訊 Omi-chart 正式釋出

v1.0.1 omi-chart 一個 chart-x 標籤搞定資料視覺化, omi 和 chart.js強力加持 支援的圖表 <chart-bar /> 柱狀圖 <chart-line /> 線圖 <chart-scatter

開源騰訊 Omio 釋出 - 全面相容 IE9 和移動端

寫在前面 在微信支付、手機QQ、騰訊TEG、騰訊IEG等團隊已經能夠使用 Omi 應用於大量的 to b 的專案以及內部管理系統,為了達到 Omi 全覆蓋,相容 to c 端各種瀏覽器環境,所以有了 Omio, 擁有幾乎和 Omi 一模一樣的語法。 相容老瀏覽器的 Omi 版本,→ Github

開源騰訊 omi-mp-create 釋出 - 極小卻精巧的小程式框架

【開源】騰訊 omi-mp-create 釋出 極小卻精巧的小程式框架,對小程式入侵性幾乎為零 → Github omi-mp-create 和 omio 一樣,使用了 omi packages 裡的 obaa 監聽資料變化自動更新檢視。和早期釋出的 westore 對比的話,

開源PaaS Rainbond v3.6.0正式釋出Service Mesh開箱即用_Kubernetes中文社群

Rainbond是以應用為中心的開源PaaS,由好雨基於Docker、Kubernetes等容器技術自主研發,可作為公有云或私有云環境下的應用交付平臺、DevOps平臺、自動化運維平臺和行業雲平臺,或作為企業級的混合雲多雲管理工具、kubernetes容器管理工具或Service Mesh微服

walle 2.0.0 正式釋出可能是春節前最良心的免費開源部署工具

   walle-web.io 大概是最為矚目的免費開源的上線部署平臺的新星,讓使用者程式碼釋出終於可以不只能選擇 jenkins,支援各種web程式碼釋出,php、java等程式碼的釋出、回滾可以通過web來一鍵完成。walle 一個可自由配置專案,更人性化,高顏值

開源C#.NET股票歷史資料採集附18年曆史資料和原始碼

重點重點:我沒有買股票,沒有買股票,股市是個坑,小心割韭菜哦。 本文的初衷是資料分析(分析結果就不說了,就是想看看篩選點資料),只不過搞下來發現比我想象的要簡單多了。本文采集的資料是:2000年到2018年2月份,上證和深證交易所所有的上市股票交易資料,按天採集,不是小時哦,有興趣的朋友,可以稍微改

開源小程式、小遊戲和Web運動引擎 to2to 釋出

簡單輕量跨平臺的 Javascript 運動引擎 to2to 中文念 '兔兔兔',作為 cax 內建的運動套件獨立出一個package ,因為它本身可以和平臺環境運動物件無關。既可運動 dom,也可運動 cax 內建物件,也可運動物件子面量。眾所周知,運動需要迴圈的 tick 去不斷執行偏移函式,小程式

開源簡單4步搞定QQ登入無需什麼程式碼功底無語言界限

說17號發超簡單的教程就17號,qq核審通過後就封裝了這個,現在放出來~~ 這個是我封裝的一個開源專案:https://github.com/dunitian/LoTQQLogin ———————————————————————————————————————————— 先申請一下 建立一個應用

開源1句程式碼搞定圖片批量上傳無需什麼程式碼功底無語言界限

/// <summary> /// 圖片上傳 /// </summary> /// <returns></returns> public JsonResult Upload(HttpPo

開源簡單4步搞定QQ登入無需什麼程式碼功底無語言界限下 ~ Net程式設計師的福利

這次我們專門為Net程式設計師準備一個專版(其他方向的看通用封裝即可,使用起來很簡單) 做個簡單的案例:(EF+MVC) 1.先看一下自己的appid 2.前臺一系列設定:(圖片看不見的話點開看,會放大的) 3.資料庫設計(簡單版本) 4.Model類 5.後臺處理(不同框架處

華為軟體開發雲又出新服務:開源映象站正式上線致敬開源使能開發者!

映象庫使用有疑問?有建議?要吐槽?依賴管理工具相關資料難獲取?疑難問題求助?華為開源映象站對接了軟體開發雲論壇,給大家提供跟映象庫、依賴管理工具相關的使用和學習資料,讓你能更便捷的找到所有需要配套的內容,更好的使用映象庫。同時,論壇也是一個大家交流學習的地方,任何疑問和建議我們都會及時答覆和支援。

Python、C++、R 三合一效果好Julia 重磅釋出全球熱度上升最快

IT派助力深廣創業,免費代發招聘資訊,瞭解一下?

開源NodeJS仿WebApi路由

ole ati amt nbsp amd 使用 ise erp 一個 用過WebApi或Asp.net MVC的都知道微軟的路由設計得非常好,十分方便,也十分靈活。雖然個人看來是有的太靈活了,team內的不同開發很容易使用不同的路由方式而顯得有點混亂。 不過這不是重點,我在

PHP開發經驗之談看了受益非淺

his 則表達式 處理 手冊 調用 緩存系統 字符串操作函數 如果能 諸多 用單引號代替雙引號來包含字符串,這樣做會更快一些。因為PHP會在雙引號包圍的字符串中搜尋變量,單引號則不會,註意:只有echo能這麽做,它是一種可以把多個字符串當作參數的“函數”(譯註:PHP手冊中

開源OSharp框架學習系列(1):總體設計及系列導航

正是 html 組織 內聚性 權限 是什麽 enc 3-0 分發 OSharp是什麽?   OSharp是個快速開發框架,但不是一個大而全的包羅萬象的框架,嚴格的說,OSharp中什麽都沒有實現。與其他大而全的框架最大的不同點,就是OSharp只做抽象封裝,不做實現。依賴註