日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

DataQL

發(fā)布時(shí)間:2023/12/16 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 DataQL 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡介

DataQL(Data Query Language)DataQL 是一種查詢語言。旨在通過提供直觀、靈活的語法來描述客戶端應(yīng)用程序的數(shù)據(jù)需求和交互。

數(shù)據(jù)的存儲(chǔ)根據(jù)其業(yè)務(wù)形式通常是較為簡單的,并不適合直接在頁面上進(jìn)行展示。因此開發(fā)頁面的前端工程師需要為此做大量的工作,這就是 DataQL 極力解決的問題。

請(qǐng)注意 DataQL 不是一門編程語言,它是查詢語言。它對(duì)邏輯的處理僅限于簡單場景。DataQL 的解決問題的重點(diǎn)集中在:數(shù)據(jù)的聚合和轉(zhuǎn)換以及過程中的簡單加工處理。

特性

  • 層次結(jié)構(gòu):多數(shù)產(chǎn)品都涉及數(shù)據(jù)的層次結(jié)構(gòu),為了保證結(jié)構(gòu)的一致性 DataQL 結(jié)果也是分層的。
  • 數(shù)據(jù)為中心:前端工程是一個(gè)比較典型的場景,但是 DataQL 不局限于此(后端友好性)。
  • 弱類型定義:語言中不會(huì)要求聲明任何形式的類型結(jié)構(gòu)。
  • 簡單邏輯:具備簡單邏輯處理能力:表達(dá)式計(jì)算、對(duì)象取值、條件分支、lambda和函數(shù)。
  • 編譯運(yùn)行:查詢的執(zhí)行是基于編譯結(jié)果的。
  • 混合語言:允許查詢中混合任意的其它語言代碼,典型的場景是查詢中混合 SQL 查詢語句。
  • 類 JS 語法:類JS語法設(shè)計(jì),學(xué)習(xí)成本極低。
  • 語法手冊(cè)

    詞法記號(hào)
    • 注釋支持://、/*…*/

    • 支持任意空格,提高可讀性,支持\t,\n,\r,\f

    • 關(guān)鍵字:

      關(guān)鍵字含義
      if條件語句的引導(dǎo)詞
      else用在條件語句中,表明當(dāng)條件不成立時(shí)的分支
      return三大退出指令之一,終止當(dāng)前過程的執(zhí)行并正常退出到上一個(gè)執(zhí)行過程中
      throw三大退出指令之一,終止所有后續(xù)指令的執(zhí)行并拋出異常
      exit三大退出指令之一,終止所有后續(xù)指令的執(zhí)行并正常退出
      var執(zhí)行一個(gè)查詢動(dòng)作,并把查詢結(jié)果保存到臨時(shí)變量中
      run僅僅執(zhí)行查詢動(dòng)作,不保留查詢的結(jié)果
      hint寫在 DataQL 查詢語句的最前面,用于設(shè)置一些執(zhí)行選項(xiàng)參數(shù)
      import將另外一個(gè) DataQL 查詢導(dǎo)入并作為一個(gè) Udf 形式存在、或直接導(dǎo)入一個(gè) Udf 到當(dāng)前查詢中
      as與 import 關(guān)鍵字配合使用,用作將導(dǎo)入的 Udf 命名為一個(gè)本地變量名
      true基礎(chǔ)類型之一,表示 Boolean 的:真值
      false基礎(chǔ)類型之一,表示 Boolean 的:假值
      null基礎(chǔ)類型之一,表示 NULL 值
    • 標(biāo)識(shí)符:表示查詢中的一些實(shí)體,如變量名參數(shù)名。必須滿足正則表達(dá)式:[_a-zA-Z][_0-9a-zA-Z]*,一些對(duì)象的key可能會(huì)超出范圍,可以用反引號(hào)`xxx`。

    • 分隔符:()、{}、[]、,、:、;(非必須)

    • 運(yùn)算符:

    • 數(shù)學(xué)運(yùn)算:+,-,*,/,\(整除),%
    • 位運(yùn)算:&,|,!,^(異或),<<(左位移),>>(有符號(hào)右位移),>>>(無符號(hào)右位移)
    • 比較運(yùn)算:>,>=,<,<=,==,!=
    類型系統(tǒng)

    DataQL 是弱類型定義的查詢語言,在DataQL 中所有數(shù)據(jù)都會(huì)被歸結(jié)到有限的幾種類型上。無需定義數(shù)據(jù)類型結(jié)構(gòu),在弱類型系統(tǒng)中編寫查詢會(huì)非常方便,它去掉了繁雜的類型定義。

    數(shù)據(jù)類型表示方式詳情
    布爾truefalse表示真假值
    數(shù)值負(fù)無窮大0正無窮大浮點(diǎn)數(shù)、整數(shù)、科學(xué)計(jì)數(shù)法表示的數(shù)
    字符串’ 或 “字符串 或 單個(gè)字符
    空值nullNULL空值
    集合[…] 數(shù)組 或 多維數(shù)組帶有順序的多組數(shù)據(jù)的集合
    對(duì)象{‘key’:…} 具有鍵值對(duì)的數(shù)據(jù)體DataQL 的對(duì)象不支持方法,但是可以具備 Udf 類型的屬性。
    UDFlambda 函數(shù) 或 一個(gè)外部的 Udf一個(gè)外部的 net.hasor.dataql.Udf 接口函數(shù)定義。
    DataQL 中書寫的 lambda 函數(shù)也被稱作為 UDF。
    一個(gè)擴(kuò)展代碼片段的定義,也屬于 UDF 的范疇。
    • 數(shù)值類型

      • 二進(jìn)制表示法:0b010101011000B01010101100
      • 十進(jìn)制表示法:0o12345670O1234567
      • 八進(jìn)制表示法:-0000234123
      • 十六進(jìn)制表示法:0x123450X12345
      • 科學(xué)計(jì)數(shù)法:a * 10的n 次冪的形式,其中 1 < a < 10
      • 關(guān)于負(fù)數(shù):目前只有十進(jìn)制表示法中提供了負(fù)數(shù)的表示能力。
    • UDF

      • 外部Udf:外部的 Udf 被引入之后,通常以標(biāo)識(shí)符形式表示它。
      • DataQL 中書寫的 lambda 表達(dá)方式為:var foo = () -> { /* 代碼塊 */ }
      • 外部代碼片段:var a = @@xxx() <% /* 外部代碼塊 */ %>
    • JSON

      • DataQL 可以直接表達(dá) Json 數(shù)據(jù)(Json 的 Key 必須通過雙引號(hào)或單引號(hào)形式包裹起來)
    • 當(dāng)兩類型不匹配時(shí)能自動(dòng)類型提升。

    數(shù)值
    • 支持:byte、short、int、long、float、double、BigInt、Decimal

    • 數(shù)值寬度默認(rèn)是int和double

    • 浮點(diǎn)數(shù)計(jì)算時(shí)默認(rèn)保留20位小數(shù),多余的四舍五入。修改精度使用hint MAX_DECIMAL_DIGITS=20,更換舍入規(guī)則hint NUMBER_ROUNDING = 'HALF_EBEN'。

    語句
    • import

      • import “<函數(shù)類或函數(shù)包類>” as <別名>
      • import @"<資源地址>" as <別名>
      • 別名必須滿足 標(biāo)識(shí)符
      • 必須放在整個(gè)查詢最開始的地方,被導(dǎo)入的資源會(huì)以var的方式定義。
    • var

      • var <變量名> = <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
      • 定義變量、執(zhí)行并存儲(chǔ)表達(dá)式的值
    • run

      • run <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
    • return、throw、exit

      • return <狀態(tài)碼>, <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
      • 還可以不指定狀態(tài)碼
      • return <表達(dá)式 or 值對(duì)象 or 函數(shù)定義>
      • 三者除了行為不同,用法完全一樣。
    • if

      • 令DataQL變得靈活的存在

      • if` `(boolean_expression) {``/* 如果布爾表達(dá)式為真將執(zhí)行的語句 */ } ``else` `{``/* 如果布爾表達(dá)式為假將執(zhí)行的語句 */ }
    • hint

      • hint <選項(xiàng)名稱> = <選項(xiàng)值>
      • 作用是設(shè)置一些執(zhí)行查詢使用的選項(xiàng)參數(shù)。可以參考這里
    表達(dá)式
    • 一元運(yùn)算:!(對(duì)Boolean取反),-(對(duì)數(shù)值取相反數(shù))
    • 二元運(yùn)算:主要是面向number,但是也支持字符串拼接。
    • 三元運(yùn)算:testExpr ? expr1 : expr2
    訪問符
    • 取值域:

      • $:值域符A
      • #:值域符B
      • @:值域符C
      • 應(yīng)用場景:1. 獲取程序傳來的參數(shù)。2. 表達(dá)式中的訪問符。
    • 獲取程序傳來的參數(shù):<訪問符>{<參數(shù)名>} ,如${abc}

    • 表達(dá)式中的訪問符:$(環(huán)境棧根),#(環(huán)境棧頂),@(整個(gè)環(huán)境棧(數(shù)組形態(tài)))

      • DataQL 查詢過程中一般情況下環(huán)境棧始終是空的,當(dāng)遇到 => 操作時(shí)。

        DataQL 會(huì)把 => 符左邊的表達(dá)式值放入環(huán)境棧,當(dāng)轉(zhuǎn)換結(jié)束時(shí) DataQL 會(huì)把表達(dá)式值從環(huán)境棧中刪掉。

        如果在轉(zhuǎn)換過程中遇到第二次 => 操作,那么會(huì)在環(huán)境棧頂中放入新的數(shù)據(jù)。

    取值與賦值
    • 對(duì)象取值:return userInfo.username;

    • 函數(shù)結(jié)果取值:return userByID({'id': 4}).username;

    • 數(shù)組中取值:return userList()[0].username;

    • 下標(biāo)取值:return userInfo['username'];

    • 連續(xù)下標(biāo)取值:return userList[0]['username'];

    • 數(shù)組下標(biāo)取值:

      • 正向索引:list[3] = 3,
      • 反向索引:list[-3] = 7,
      • 索引溢出:三種處理方式:throw,null,near(默認(rèn))
    • 下標(biāo)變量:使用變量代替下標(biāo)

      // 定義一個(gè)變量,變量表示要取值的字段名。 var columnKey = 'username'; // 通過下標(biāo)變量方式來取值 return userInfo[columnKey];
    • 賦值

      • 在DataQL中數(shù)據(jù)是不可被修改的只能重新生成數(shù)據(jù)集或者在結(jié)果轉(zhuǎn)換中對(duì)局部數(shù)據(jù)進(jìn)行修改。
      • 重定義: 在任何時(shí)候都可以通過var來重新定義一個(gè)已經(jīng)存在的變量。
    結(jié)果轉(zhuǎn)換
    • 結(jié)果轉(zhuǎn)換是DataQL的核心能力,可以大體歸納為:組裝(憑空構(gòu)造)和變換。

    • 組裝:

      • case1:

        var userName = "馬三"; // 姓名 var userAge = 23; // 年齡// 返回一個(gè)對(duì)象數(shù)據(jù),將用戶名稱和年齡組裝到一個(gè)對(duì)象中 return {"name" : userName,"age" : userAge };
      • case2:

        var data1 = 123; // 值1 var data2 = 456; // 值2// 返回2個(gè)元素的數(shù)組 return [data1, data2 ];
      • case3:

        var data = [123, 456];//它組裝了兩個(gè)字段。但是兩個(gè)字段分別來自于同一個(gè)數(shù)組數(shù)據(jù)的不同元素 return {"element_0" : data[0], // 123"element_1" : data[1] // 456 };
    • 數(shù)組的變換(是一個(gè)一個(gè)元素依次按照規(guī)則進(jìn)行轉(zhuǎn)換的)

      //首先我們有一個(gè)對(duì)象數(shù)組 var data = [{"userID" : 1234567891,"age" : 31,"name" : "this is name1.","nick" : "my name is nick1.","sex" : "F","status" : true },{"userID" : 1234567892,"age" : 32,"name" : "this is name2.","nick" : "my name is nick2.","sex" : "F","status" : true },{"userID" : 1234567893,"age" : 33,"name" : "this is name3.","nick" : "my name is nick3.","sex" : "M","status" : true } ]
      • case1:

        //得到一個(gè)新的數(shù)據(jù)集,只包含name和age字段 return data => [{"name", "age"} ];
      • case2:

        //只包含name和age字段,同時(shí)修改一下字段名 return data => [{"userName" : name, // 取 name 字段的值作為 userName 的值"userAge" : age} ];
      • case3:

        //返回所有用戶名的列表,得到字符串?dāng)?shù)組 return data => [ name ];
      • case4:

        //將 一組值類型 變換成 一組對(duì)象 var data = ["馬三", "馬四"]; return data => [{"name" : # // 符號(hào) "#" 表示在對(duì)每個(gè)元素進(jìn)行轉(zhuǎn)換的過程中的那個(gè)元素本身。} ]; //得到的就是 [ {"name":"馬三"}, {"name":"馬四"} ]
      • case5:

        //為二維數(shù)組的每個(gè)值都加上一個(gè)字符串前綴 var data = [[1,2,3],[4,5,6],[7,8,9] ] return data => [# => [ // 在結(jié)果轉(zhuǎn)換中對(duì)當(dāng)前元素進(jìn)行二次轉(zhuǎn)換"值:" + #] ] //查詢結(jié)果: [["值:1","值:2","值:3"],["值:4","值:5","值:6"],["值:7","值:8","值:9"] ]
    • 對(duì)象的變換

      //首先我們有一個(gè)對(duì)象 var data = {"userID" : 1234567890,"age" : 31,"name" : "this is name.","nick" : "my name is nick.","sex" : "F","status" : true }
      • case1:

        //通過變換而非組裝的方式將其轉(zhuǎn)換為一個(gè)數(shù)組,內(nèi)容是一個(gè)對(duì)象 return data => [ # ]; //---------結(jié)果--------- [{"userID": 1234567890,"age": 31,"name": "this is name.","nick": "my name is nick.","sex": "F","status": true} ]
      • case2:

        //對(duì)象的變換通常都是結(jié)構(gòu)上的變化。對(duì)象可以是數(shù)組形式的一個(gè)元素,數(shù)組中可以疊加對(duì)象的變換 return data => {"name","info" : {"age","sex"} } //查詢結(jié)果 {"name": "this is name.","info": {"age": 31,"sex": "F"} }
    • 使用表達(dá)式

      • case1:

        //對(duì)結(jié)果變換過程中通過表達(dá)式來對(duì)字段重新計(jì)算 return data => {"name","age" : age + "歲","old" : age, // 這是有效的,age能夠使用多次"old" : name, // 這是無效的,"old"只會(huì)顯示上面那個(gè)"sex" : (sex == 'F') ? '男' : '女' }
    • 通過Lambda模擬for循環(huán)

      import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;var map = {"a" : 123,"b" : 321 } var data = [{"name" : "馬三","type" : "a"},{"name" : "n2","type" : "b"} ]var appendData = (dat) -> {//這個(gè)dat是data中的一個(gè)對(duì)象。lambda表達(dá)式只用處理一個(gè)元素即可,具體的整個(gè)數(shù)組的調(diào)用邏輯在return的時(shí)候。var newMap = collect.newMap(dat);run newMap.put('type',map[dat.type])//給這個(gè)newMap中設(shè)置'type'屬性,值是這樣取出來的(從map取出(key是(dat.type的value)的鍵值對(duì))的值)。return newMap.data() };return data => [appendData(#) ] // 變量appendData定義為一個(gè)函數(shù),這個(gè)函數(shù)有一個(gè)參數(shù)。 // 對(duì)data進(jìn)行變換時(shí),變換規(guī)則是之前定義的函數(shù)appendData, // 在這個(gè)函數(shù)中參數(shù)為當(dāng)前data數(shù)組中的一個(gè)對(duì)象元素, // 所以在函數(shù)中是對(duì)一個(gè)對(duì)象進(jìn)行操作,不用考慮數(shù)組的問題。 // 數(shù)組是在return的時(shí)候?qū)erson進(jìn)行變換,對(duì)每個(gè)元素#調(diào)用定義的lambda函數(shù)appendData實(shí)現(xiàn)的。//執(zhí)行結(jié)果 [{"name": "馬三","type": 123},{"name": "n2","type": 321} ]
    • Tips:

    • 變換要出現(xiàn)數(shù)組,則以[]包裹,對(duì)象則{}包裹,只有[]沒有{}的是字符串?dāng)?shù)組。在變換中能自由改名并使用表達(dá)式組合結(jié)果,并且可以一個(gè)元素多次使用,但是同名屬性只以第一次出現(xiàn)為準(zhǔn)。
    • 對(duì)數(shù)組的循環(huán)操作可以通過,在return中對(duì)數(shù)組取#實(shí)現(xiàn)對(duì)每個(gè)元素的更改。
    函數(shù)
    • 定義函數(shù):可以直接用DataQL語言定義一個(gè)函數(shù),然后在后續(xù)查詢中使用它。

      var convertSex = (sex) -> {//定義一個(gè)函數(shù)return (sex == 'F') ? '男' : '女' };var data = {"userID" : 1234567890,"age" : 31,"name" : "this is name.","nick" : "my name is nick.","sex" : "F","status" : true };return data => {"name","age" : age + "歲","sex" : convertSex(sex)//使用函數(shù)得到值 }
    • 外部函數(shù):DataQL具有官方標(biāo)準(zhǔn)函數(shù)庫,可以通過import語句導(dǎo)入。

      //通過時(shí)間函數(shù)庫獲取時(shí)間 import 'net.hasor.dataql.fx.basic.DateTimeUdfSource' as time;return time.now();//通過json函數(shù)庫來生成JSON數(shù)據(jù) import 'net.hasor.dataql.fx.basic.JsonUdfSource' as json;return json.toJson([0,1,2])// "[0,1,2]"
      • 開發(fā)者還可以自己編寫函數(shù)(編寫UDF)
    • Lambda寫法

      import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect; // 數(shù)據(jù) var dataList = [{"name" : "馬一" , "age" : 18 },{"name" : "馬二" , "age" : 28 },{"name" : "馬三" , "age" : 30 },{"name" : "馬四" , "age" : 25 } ]//只保留年齡大于20歲的數(shù)據(jù)// 使用非Lambda的寫法---------------- // 年齡過濾邏輯 var filterAge = (dat) -> {return return dat.age > 20; }; // 調(diào)用 filter 函數(shù) return collect.filter(dataList, filterAge);//使用Lambda的寫法----------------------省略了一個(gè)函數(shù)定義 var result = collect.filter(dataList, (dat) -> { // lambda 寫法return dat.age > 20;// 年齡過濾條件 });
    混合其他語言

    ? 在DataQL中混合其他語言一起協(xié)同處理DataQL查詢,需要定義一個(gè)片段執(zhí)行器。

    • 典型的場景是把SQL語句混合在DataQL中。

      var dataSet = @@sql(item_code) <%select * from category where co_code = #{item_code} %>return dataSet() => [{ "id","name","code","body" } ] // @@sql 是 FunctionX 擴(kuò)展包中提供的一組片段執(zhí)行器,這個(gè)片段執(zhí)行器相當(dāng)于讓 DataQL 有能力執(zhí)行數(shù)據(jù)庫的 SQL 語句。
    • 定義:定義一個(gè)片段執(zhí)行器需要,實(shí)現(xiàn) net.hasor.dataql.FragmentProcess 接口(更多信息請(qǐng)參考開發(fā)手冊(cè))并且將其注冊(cè)到 DataQL 環(huán)境中

      // 方式一:通過Dataql接口 FragmentProcess process = ... AppContext = appContext = ...DataQL dataQL = appContext.getInstance(DataQL.class);//獲取 DataQL 接口 dataQL.addFragmentProcess("sql", process); //注冊(cè)片段執(zhí)行器// 方式二:通過QueryModule FragmentProcess process = ...public class MyQueryModule implements QueryModule {public void loadModule(QueryApiBinder apiBinder) {dataQL.addFragmentProcess("sql", process); //注冊(cè)片段執(zhí)行器} }
    • 使用:

      定義一個(gè)片段執(zhí)行器需要使用 @@xxxx(arg1,arg2,arg3,…)<% … %> 語法,其中:

      • xxxx 為片段執(zhí)行器注冊(cè)的名稱。
      • (arg1,arg2,arg3,…) 為執(zhí)行這個(gè)代碼時(shí)傳入的參數(shù)列表。如果不需要定義任何參數(shù)可以是 ()
      • <%%> 之間編寫的是 目標(biāo)語言的代碼片段。
      // 在 MySQL 中插入一條數(shù)據(jù),并返回自增的ID var saveData = @@sql(data) <%insert into my_option (`key`,`value`,`desc`) values (#{data.key},#{data.value},#{data.desc});select LAST_INSERT_ID(); %> return saveData(${root});

    數(shù)據(jù)模型

    DataQL的數(shù)據(jù)模型是通過net.hasor.dataql.domain.DataModel接口表示的,共計(jì)4個(gè)實(shí)現(xiàn)類:ValueModel,ListModel,ObjectModel,UdfModel。

    還有一個(gè)非常重要的unwrap方法,能解除DataModel形態(tài)的封裝,直接變成Map/List結(jié)構(gòu),注意UdfModel類型解開是Udf接口。

    • ValueModel:用于表示String、Number、Boolean、Null四種基本數(shù)據(jù)類型。有isXxx()方法用于判斷類型,asXxx()方法用于獲取對(duì)應(yīng)值。
    • ListModel:表示一個(gè)列表或集合的數(shù)據(jù),相比較 DataModel 多了一組根據(jù)元素位置判斷對(duì)應(yīng)類型的接口方法。
    • ObjectModel:表示一個(gè)列表或集合的數(shù)據(jù),相比較 DataModel 多了一組根據(jù)元素 Key 判斷對(duì)應(yīng)類型的接口方法。
    • UdfModel:當(dāng) DataQL 查詢返回一個(gè) Udf 函數(shù)或者 Lambda 函數(shù)時(shí),就會(huì)得到一個(gè) UdfModel。而它事實(shí)上就是一個(gè) Udf

    開發(fā)手冊(cè)

    執(zhí)行查詢

    ? 引入依賴

    <dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql</artifactId><version>4.2.1</version> </dependency>
  • 通過Hasor使用DataQL

    //由于 AppContext 有自身的聲明周期特性,因此需要做一個(gè)單例模式來創(chuàng)建 DataQL 接口。 public class DataQueryContext {private static AppContext appContext = null;private static DataQL dataQL = null;public static DataQL getDataQL() {if (appContext == null) {appContext = Hasor.create().build();dataQL = appContext.getInstance(DataQL.class);}return dataQL;} }//然后在Test中執(zhí)行查詢 HashMap<String, Object> tempData = new HashMap<String, Object>() {{put("uid", "uid is 123");put("sid", "sid is 456"); }};DataQL dataQL = DataQueryContext.getDataQL(); Query dataQuery = dataQL.createQuery("return [${uid},${sid}]"); QueryResult queryResult = dataQuery.execute(tempData); DataModel dataModel = queryResult.getData(); List list = (List)dataModel.unwrap();for (Object o : list) {System.out.println(o);}
  • 通過JSR223使用DataQL:我這里略

  • 基于底層接口使用DataQL

    DataQL 的運(yùn)行基于三個(gè)步驟:

    • 1.解析DataQL查詢:把 DataQL 查詢字符串通過解析器解碼為 AST(抽象語法樹)QueryModel queryModel = QueryHelper.queryParser(query1);
    • 2.編譯查詢:將DataQL 的 AST(抽象語法樹) 編譯為 QIL 指令序列。QIL qil = QueryHelper.queryCompiler(queryModel, ``null``, Finder.DEFAULT);
    • 3.執(zhí)行查詢:最后在根據(jù) QIL 創(chuàng)建對(duì)應(yīng)的 Query 接口即可。Query dataQuery = QueryHelper.createQuery(qil, Finder.DEFAULT);
  • 查詢接口(Query)
    無論使用何種方式查詢都會(huì)通過DataQL的查詢接口發(fā)出查詢指令。

    查詢接口提供了三種不同參數(shù)類型的查詢重載,所有入?yún)?shù)最后都被轉(zhuǎn)換成為 Map 結(jié)構(gòu)然后統(tǒng)一變換成為 CustomizeScope 數(shù)據(jù)域形式。

  • 查詢結(jié)果(QueryResult)

    發(fā)出DataQL查詢后,如果順利執(zhí)行完查詢,結(jié)果會(huì)以QueryResult接口形式返回。

    /** 執(zhí)行結(jié)果是否通過 EXIT 形式返回的 */ public boolean isExit();/** 獲得退出碼。如果未指定退出碼,則默認(rèn)值為 0 */ public int getCode();/** 獲得返回值 */ public DataModel getData();/** 獲得本次執(zhí)行耗時(shí) */ public long executionTime();

    DataQL 的所有返回值都會(huì)包裝成 DataModel 接口類型。如果想拿到 Map/List 結(jié)構(gòu)數(shù)據(jù),只需要調(diào)用 unwrap 方法即可。

  • 全局變量

    添加全局變量有兩種方式:

  • 在QueryModule中初始化環(huán)節(jié)添加

    AppContext appContext = Hasor.create().build((QueryModule) apiBinder -> {apiBinder.addShareVarInstance("global_var", "g1"); });
  • 通過DataQL接口添加

    DataQL dataQL = appContext.getInstance(DataQL.class); dataQL.addShareVarInstance("global_var", "g2");
  • 獲取全局變量

    return global_var;
  • 函數(shù)
    • 開發(fā)Udf

      一個(gè)Udf必須是實(shí)現(xiàn)了net.hasor.dataql.Udf接口,注冊(cè)Udf的方式和添加全局變量相同。

      public class UserByIdUdf implements Udf {private UserManager userManager;public Object call(Hints readOnly, Object[] params) {return userManager.findById(params[0]);} }
    • 參數(shù)中的Udf

      DataQL 允許在執(zhí)行查詢時(shí)通過參數(shù)形式提供 Udf ,這種方式傳入的 Udf 在調(diào)用時(shí)也需要使用 ${…} 來獲取

      HashMap<String, Object> tempData = new HashMap<String, Object>() {{put("findUserById", new UserByIdUdf()); }};AppContext appContext = Hasor.create().build(); DataQL dataQL = appContext.getInstance(DataQL.class);//得到 DataQL接口 Query dataQuery = dataQL.createQuery("return ${findUserById}(1) => { 'name','sex' }"); // 創(chuàng)建查詢 QueryResult queryResult = dataQuery.execute(tempData); DataModel dataModel = queryResult.getData();
    • 函數(shù)包(UdfSource)

      UdfSource 是一個(gè)函數(shù)包接口,接口中只有一個(gè) getUdfResource 方法,用于返回函數(shù)包中的所有 Udf(Map形式返回)但是一般情況下更推薦使用 UdfSourceAssembly 接口。

      使用函數(shù)包的好處是可以像平常開發(fā)一樣編寫 Udf,無需考慮 Udf 接口的細(xì)節(jié)。裝配器會(huì)自動(dòng)幫助進(jìn)行參數(shù)和結(jié)果的轉(zhuǎn)換。

      public class DateTimeUdfSource implements UdfSourceAssembly {/** 返回當(dāng)前時(shí)間戳 long 格式 */public long now() { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:年 */public int year(long time) { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:月 */public int month(long time) { ... }/** 返回當(dāng)前系統(tǒng)時(shí)區(qū)的:日 */public int day(long time) { ... }... } // 最后在查詢中通過 <函數(shù)包名>.<函數(shù)> 的形式調(diào)用函數(shù)包。
    • inport導(dǎo)入(函數(shù)/函數(shù)包)

      如果 Classpath 中已經(jīng)存在某個(gè) Udf 類,還可以通過 import 語句導(dǎo)入使用。

      import 'net.xxxx.foo.udfs.UserByIdUdf' as findUserById; return findUserById(1) => { 'name','sex' };

      函數(shù)包的導(dǎo)入語句相同,只是在調(diào)用函數(shù)包中函數(shù)的時(shí)需要指明函數(shù)包

      import 'net.xxxx.foo.udfs.DateTimeUdfSource' as timeUtil; return timeUtil.now();
    • 使用注解批量注冊(cè)

      通過 @DimUdf 注解可以快速的聲明函數(shù)

      @DimUdf("findUserById") public class UserByIdUdf implements Udf {private UserManager userManager;public Object call(Hints readOnly, Object[] params) {return userManager.findById(params[0]);} }

      通過 @DimUdfSource 注解可以快速的聲明函數(shù)包:

      @DimUdfSource("time_util") public class DateTimeUdfSource implements UdfSourceAssembly {... }

      然后在初始化時(shí)掃描加載它們

      AppContext appContext = Hasor.create().build(apiBinder -> {QueryApiBinder queryBinder = apiBinder.tryCast(QueryApiBinder.class);queryBinder.loadUdf(queryBinder.findClass(DimUdf.class));queryBinder.loadUdfSource(queryBinder.findClass(DimUdfSource.class)); });
    外部代碼片段
    • 外部代碼執(zhí)行器

      外部代碼片段是 DataQL 特有能力,它允許在 DataQL 查詢中混合其它語言的腳本。并將引入的外部語言腳本轉(zhuǎn)換為 Udf 形式進(jìn)行調(diào)用。使用這一特性時(shí)需要擴(kuò)展 FragmentProcess 接口,并注冊(cè)對(duì)應(yīng)的外部代碼執(zhí)行器

      //外部代碼執(zhí)行器,接收<% %>包裹的代碼,然后調(diào)用jdbcTemplate的query方法執(zhí)行具體的SQL查詢 @DimFragment("sql") public class SqlQueryFragment implements FragmentProcess {@Injectprivate JdbcTemplate jdbcTemplate;public Object runFragment(Hints hint, Map<String, Object> paramMap, String fragmentString) throws Throwable {return this.jdbcTemplate.queryForList(fragmentString, paramMap);} }//在初始化階段注冊(cè)這個(gè)代碼執(zhí)行器,就可以在查詢時(shí)使用了這個(gè)外部代碼片段了 public class MyFragment implements QueryModule {public void loadModule(QueryApiBinder apiBinder) {//掃描所有標(biāo)記了@DimFragment注解的類并加載它apiBinder.loadFragment(queryBinder.findClass(DimFragment.class));} }//DataQL語句,通過@@指令開啟了一段外部代碼的定義,執(zhí)行器的名字是sql var dataSet = @@sql(item_code) <%select * from category where co_code = #{item_code} %>return dataSet() => [{ "id","name","code","body" } ]
    • 資源加載器(Finder)

      資源加載器是net.hasor.dataql.FInder,其主要負(fù)責(zé)import語句導(dǎo)入資源/對(duì)象的加載。通常不會(huì)接觸到它。

      import ``'userBean'` `as ub;``//userBean 是 Bean 的名字 return` `ub().name;

    SQL執(zhí)行器

    SQL 執(zhí)行器是 DataQL 的一個(gè) FragmentProcess 擴(kuò)展,其作用是讓 DataQL 可以執(zhí)行 SQL。執(zhí)行器的實(shí)現(xiàn)是 FunctionX 擴(kuò)展包提供的。使用執(zhí)行器需要引入擴(kuò)展包。

    <dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql-fx</artifactId><version>4.2.1</version> </dependency>
    功能與特性
    • 支持兩種模式:簡單模式分頁模式
    • 簡單模式下,使用原生SQL。100% 兼容所有數(shù)據(jù)庫
    • 分頁模式下,自動(dòng)改寫分頁SQL。并兼容多種數(shù)據(jù)庫
    • 支持參數(shù)化 SQL,更安全
    • 支持 SQL 注入,更靈活
    • 支持批量 CURD
    配置和方言
    • 配置數(shù)據(jù)源

      //普通方式配置數(shù)據(jù)源,在Hasor中初始化數(shù)據(jù)源即可 public class ExampleModule implements Module {public void loadModule(ApiBinder apiBinder) throws Throwable {// .創(chuàng)建數(shù)據(jù)源DataSource dataSource = null;// .初始化Hasor Jdbc 模塊,并配置數(shù)據(jù)源apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));} }
    • 方言

      配置方言使用 hint HASOR_DATAQL_FX_PAGE_DIALECT = mysql,即可設(shè)置方言。支持Mysql,Oracle,SqlServer2012,PostgreSQL,DB2,Infomix。

    執(zhí)行SQL
    • 執(zhí)行SQL

      // 聲明一個(gè) SQL var dataSet = @@sql() <%select * from category limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet();
    • SQL參數(shù)化

      // 聲明一個(gè) SQL var dataSet = @@sql(itemCode) <%select * from category where co_code = #{itemCode} limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet(${itemCode});
    • SQL注入

      //SQL注入是為了一些特殊場景需要拼接SQL而準(zhǔn)備的,如:動(dòng)態(tài)排序字段和排序規(guī)則 // 使用 DataQL 拼接字符串 var orderBy = ${orderField} + " " + ${orderType};// 聲明一個(gè)可以注入的 SQL var dataSet = @@sql(itemCode,orderString) <%select * from category where co_code = #{itemCode} order by ${orderString} limit 10; %>// 執(zhí)行這個(gè) SQL,并返回結(jié)果 return dataSet(${itemCode}, orderBy);
    • Ognl表達(dá)式

      //同Mybatis一樣,SQL執(zhí)行器可以將一個(gè)對(duì)象作為參數(shù)傳入 // 例子數(shù)據(jù) var testData = {"name" : "馬三","age" : 26,"status" : 0 }// insert語句模版 var insertSQL = @@sql(userInfo) <%insert into user_info (name,age,status,create_time) values (#{userInfo.name},#{userInfo.age},#{userInfo.status},now()) %>// 插入數(shù)據(jù) return insertSQL(testData);
    • 批量操作

      DataQL 的 SQL 執(zhí)行器支持批量 Insert\Update\Delete\Select 操作,最常見的場景是批量插入數(shù)據(jù)。批量操作必須滿足下列幾點(diǎn)要求:

      • 入?yún)⒈仨毷?List
      • 如果有多個(gè)入?yún)ⅰK袇?shù)都必須是 List 并且長度必須一致
      • @@sql()<% … %> 寫法升級(jí)為批量寫法 @@sql[]()<% … %>
      • 如果批量操作的 SQL 中存在 SQL注入,那么批量操作會(huì)自動(dòng)退化為:循環(huán)遍歷模式
      • 由于批量操作底層執(zhí)行SQL使用java.sql.Statement.executeBatch方法,因此insertSQL的返回值是int數(shù)組。
      // 例子數(shù)據(jù) var testData = [{ "name" : "馬一", "age" : 26, "status" : 0 },{ "name" : "馬二", "age" : 26, "status" : 0 },{ "name" : "馬三", "age" : 26, "status" : 0 } ]// insert語句模版 var insertSQL = @@sql[](userInfo) <%insert into user_info (name,age,status,create_time) values (#{userInfo.name},#{userInfo.age},#{userInfo.status},now()) %>// 批量操作 return insertSQL(testData);
    • 執(zhí)行結(jié)果拆包

      拆包是指將只返回一行一列的數(shù)據(jù)如count(*),拆解為int類型。

      有三種模式,默認(rèn)為column

    • off:不拆包,嚴(yán)格返回一個(gè)對(duì)象數(shù)組。
    • row:最小粒度到行,多條記錄時(shí)正常返回,返回0或1條記錄時(shí),返回一個(gè)Object。
    • column:最小粒度到列,當(dāng)返回結(jié)果只有一行一列時(shí),返回具體值。
    • 拆包模式可以通過hint改變,hint FRAGMENT_SQL_OPEN_PACKAGE = 'row'

      //hint FRAGMENT_SQL_OPEN_PACKAGE = "off" var dataSet = @@sql() <% select count(*) as cnt from category; %> var result = dataSet(); // 不指定 hint 的情況下,會(huì)返回 category 表的總記錄數(shù),返回值為:10。 // 拆包模式變更為 row ,返回值為: { "cnt" : 10 } // 關(guān)閉拆包,返回值為標(biāo)準(zhǔn)的 List/Map: [ { "cnt" : 10 } ]
    • 結(jié)果列名拼寫轉(zhuǎn)換

      是指從數(shù)據(jù)庫查詢返回的列名信息,按照某一規(guī)則統(tǒng)一處理,如所有key轉(zhuǎn)為駝峰。可以使返回的列信息具有很高的可讀性。

      hint FRAGMENT_SQL_COLUMN_CASE = "hump"

      幾個(gè)可供配置的值:

      • default:保持原樣,這是個(gè)默認(rèn)設(shè)置
      • upper:全部轉(zhuǎn)大寫
      • lower:全部轉(zhuǎn)小寫
      • hump:轉(zhuǎn)換成駝峰
    • 分頁查詢

      默認(rèn)關(guān)閉,通過hint FRAGMENT_SQL_QUERY_BY_PAGE = true打開。

      打開分頁后經(jīng)過3個(gè)步驟:

      • 定義分頁SQL
      • 創(chuàng)建分頁查詢對(duì)象
      • 設(shè)置分頁信息
      • 執(zhí)行分頁查詢
      // SQL 執(zhí)行器切換為分頁模式 hint FRAGMENT_SQL_QUERY_BY_PAGE = true// 定義查詢SQL var dataSet = @@sql() <%select * from category %>// 創(chuàng)建分頁查詢對(duì)象 var pageQuery = dataSet();//從數(shù)據(jù)庫查出來的是一個(gè)對(duì)象,有多種屬性,而不是僅有數(shù)據(jù)// 設(shè)置分頁信息 run pageQuery.setPageInfo({"pageSize" : 10, // 頁大小"currentPage" : 3 // 第3頁 });// 執(zhí)行分頁查詢 var result = pageQuery.data(); // 獲取分頁信息 var info = pageQuery.pageInfo();

      由于大部分前端是以1為第一頁,而默認(rèn)情況下SQL執(zhí)行器是以0為第一頁的,所以需要-1,如果是GET方式發(fā)布的話,還需要使用轉(zhuǎn)換函數(shù)。

      import 'net.hasor.dataql.fx.basic.ConvertUdfSource' as convert; hint FRAGMENT_SQL_QUERY_BY_PAGE = true ... run queryPage.setPageInfo({"pageSize" : 5, // 頁大小"currentPage" : (convert.toInt(${pageNumber}) -1) });

      還有第二種方式,DataQL在4.1.8版本中加入FRAGMENT_SQL_QUERY_BY_PAGE_NUMBER_OFFSETHint,可以設(shè)置讓SQL執(zhí)行器以1作為開始。

    • 數(shù)據(jù)庫事務(wù)

      SQL執(zhí)行器本身并不支持事務(wù),需要借助事務(wù)函數(shù)來實(shí)現(xiàn)。

      事務(wù)函數(shù)還可以嵌套使用。

      import 'net.hasor.dataql.fx.db.TransactionUdfSource' as tran; //引入事務(wù)函數(shù) ... return tran.required(() -> {... // 事務(wù)return ... }); ...

      支持完整的7個(gè)傳播屬性:

      類型說明用法
      REQUIRED加入已有事務(wù)tran.required(() -> { … });
      REQUIRES_NEW獨(dú)立事務(wù)tran.requiresNew(() -> { … });
      NESTED嵌套事務(wù)tran.nested(() -> { … });
      SUPPORTS跟隨環(huán)境tran.supports(() -> { … });
      NOT_SUPPORTED非事務(wù)方式tran.notSupported(() -> { … });
      NEVER排除事務(wù)tran.never(() -> { … });
      MANDATORY要求環(huán)境中存在事務(wù)tran.tranMandatory(() -> { … });
    • 多數(shù)據(jù)源

      SQL執(zhí)行器在4.1.4版本之后提供了通過hint來切換數(shù)據(jù)源的能力

      public class MyModule implements Module {public void loadModule(ApiBinder apiBinder) throws Throwable {DataSource defaultDs = ...;DataSource dsA = ...;DataSource dsB = ...;apiBinder.installModule(new JdbcModule(Level.Full, defaultDs)); // 默認(rèn)數(shù)據(jù)源apiBinder.installModule(new JdbcModule(Level.Full, "ds_A", dsA)); // 數(shù)據(jù)源AapiBinder.installModule(new JdbcModule(Level.Full, "ds_B", dsB)); // 數(shù)據(jù)源B} } // 如果不設(shè)置 FRAGMENT_SQL_DATA_SOURCE 使用的是 defaultDs 數(shù)據(jù)源。 // - 設(shè)置值為 "ds_A" ,使用的是 dsA 數(shù)據(jù)源。 // - 設(shè)置值為 "ds_B" ,使用的是 dsB 數(shù)據(jù)源。 hint FRAGMENT_SQL_DATA_SOURCE = "ds_A"// 聲明一個(gè) SQL var dataSet = @@sql() <% select * from category limit 10; %> // 使用 特定數(shù)據(jù)源來執(zhí)行SQL。 return dataSet();
    • 多條查詢

      是指一次SQL執(zhí)行的過程中,包含了一個(gè)以上的SQL語句。

      var dataSet = @@sql() <%set character_set_connection = 'utf8';select * from my_option; %>return dataSet(); // 默認(rèn)返回最后一個(gè)SQL語句的結(jié)果。 // 可以通過 FRAGMENT_SQL_MUTIPLE_QUERIES hint來控制,例如:保留每一條結(jié)果。
    Mybatis執(zhí)行器

    在4.1.8版本后加入了@@Mybatis執(zhí)行器,這是對(duì)@@sql執(zhí)行器的擴(kuò)展,繼承了@@sql的能力,并提供了Mybatis的配置方式,提供了動(dòng)態(tài)SQL的能力。

    • 對(duì)比@@sql的優(yōu)勢

      • 繼承 @@sql 全部能力
      • 提供動(dòng)態(tài)SQL能力,提供 SQL 層面的 if 和 for
      • 類似 mybatis 的工作方式,比起 DataQL 拼接字符串注入更加安全可靠。
      var dimSQL = @@mybatis(userName)<%<select>select * from user_info where `name` like concat('%',#{userName},'%') order by id asc</select> %>;
    • 提供的標(biāo)簽

      • select

      • update

      • insert

      • delete

      • foreach:循環(huán)拼接SQL

        • collection:集合,必填
        • item:item,必填
        • open:起始,選填
        • close:結(jié)束,選填
        • separator:分隔符,選填
        <foreach collection="userIds.split(',')" item="userId" open="(" close=")" separator=",">#{userId} </foreach>
      • if:判斷條件,成立時(shí)拼接標(biāo)簽內(nèi)內(nèi)容

        • test:判斷條件,必填
        <if test="userId != null and userId != ''">and user_id = #{userId} </if>

    FunctionX庫函數(shù)

    依賴:

    <dependency><groupId>net.hasor</groupId><artifactId>hasor-dataql-fx</artifactId><version>4.2.1</version> </dependency>
    轉(zhuǎn)換函數(shù)庫

    引入轉(zhuǎn)換函數(shù)庫:import 'net.hasor.dataql.fx.basic.ConvertUdfSource' as convert;

    • toInt(target):將Object轉(zhuǎn)換為Number,0x12->18,""->0,“abc”->throw error
    • toString(target):將Object轉(zhuǎn)換為String,null->“null”,[1,2,3,4]->"[1, 2, 3, 4]",{“test”:123}->"{test=123}"
    • toBoolean(target):將Object轉(zhuǎn)換為Boolean,支持on,off
    • byteToHex(target):將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為十六進(jìn)制字符串,將List<Byte>轉(zhuǎn)換為String。
    • hexToByte(target):將十六進(jìn)制字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),將String轉(zhuǎn)換為List<Byte>
    • stringToByte(target, charset):將字符串轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),將String轉(zhuǎn)換為List<Byte>,charset是String類型的字符集名稱,如’utf-8’
    • ByteToString(target, charset):將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換為字符串
    集合函數(shù)庫

    引入集合函數(shù)庫:import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;

    • isEmpty:注意:collect.isEmpty(null) = false// 不支持的基本類型會(huì)返回 false

    • size

    • merge:返回 List

    • mergeMap

    • filter(dataList, filterUDF):根據(jù)一個(gè)規(guī)則來對(duì)集合進(jìn)行過濾。filterUDF類型:Udf/Lambda

      var result = collect.filter(dataList, (dat) -> {return dat.age > 20; });
    • filterMap(dataMap, keyFilterUDF)

    • limit(dataList, start, limit):截取List的一部分,返回一個(gè)List

    • newList

    • newMap(target):將一個(gè)map創(chuàng)建為帶狀態(tài)的Map,具有put(),putAll(),data(),size()方法

    • mapJoin(data_1,data_2,joinMapping):將兩個(gè)Map/List進(jìn)行左連接,joinMaping是Map類型,表示兩表的join關(guān)系。

      import 'net.hasor.dataql.fx.basic.CollectionUdfSource' as collect;var year2019 = [{ "pt":2019, "item_code":"code_1", "sum_price":2234 },{ "pt":2019, "item_code":"code_2", "sum_price":234 },{ "pt":2019, "item_code":"code_3", "sum_price":12340 },{ "pt":2019, "item_code":"code_4", "sum_price":2344 } ]; var year2018 = [{ "pt":2018, "item_code":"code_1", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_2", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_3", "sum_price":1234.0 },{ "pt":2018, "item_code":"code_4", "sum_price":1234.0 } ];var result = collect.mapJoin(year2019,year2018, { "item_code":"item_code" }) => [{"商品Code": data1.item_code,"去年同期": data2.sum_price,"今年總額": data1.sum_price,"環(huán)比去年增長": ((data1.sum_price - data2.sum_price) / data2.sum_price * 100) + "%"} ] return result;
    • mapKeyToLowerCase:將Map的Key全部轉(zhuǎn)為小寫,如果Key沖突會(huì)產(chǎn)生覆蓋

    • mapKeyToUpperCase:將Map的Key全部轉(zhuǎn)為大寫,如果Key沖突會(huì)產(chǎn)生覆蓋

    • mapKeyToHumpCase:將Map的Key中下劃線轉(zhuǎn)為駝峰,如果Key沖突會(huì)產(chǎn)生覆蓋

    • mapKeys:提取Map的Key,返回List

    • mapValues:提取Map的Values,返回List

    • mapKeyReplace(dataMap, replaceKey):循環(huán)遍歷每一個(gè)Map元素,并對(duì)Map的Key進(jìn)行替換,replaceKey是用于生成新key的函數(shù)。

      var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.mapKeyReplace(data, (oldKey,value) -> {return "new_" + oldKey }); // result = {"new_key1":1, "new_key2":2, "new_key3":3 }
    • mapValueReplace:同上,不過是對(duì)值的處理

    • list2map(listData, dataKey, convertUDF):將List轉(zhuǎn)為Map,dataKey是鍵的名字,可以用字符串,也可以直接獲取,convertUDF是轉(zhuǎn)換的函數(shù),可以不寫。

      //通過字符串指明Key字段 var yearData = [{ "pt":2018, "item_code":"code_1", "sum_price":12.0 },{ "pt":2018, "item_code":"code_2", "sum_price":23.0 },{ "pt":2018, "item_code":"code_3", "sum_price":34.0 },{ "pt":2018, "item_code":"code_4", "sum_price":45.0 } ];var result = collect.list2map(yearData, "item_code"); // result = { // "code_1": { "pt":2018, "item_code":"code_1", "sum_price":12.0 }, // "code_2": { "pt":2018, "item_code":"code_2", "sum_price":23.0 }, // "code_3": { "pt":2018, "item_code":"code_3", "sum_price":34.0 }, // "code_4": { "pt":2018, "item_code":"code_4", "sum_price":45.0 } // };//使用提取出來的值作為key var yearData = [ 1,2,3,4,5]; var result = collect.list2map(yearData, (idx,dat)-> {// Key 提取函數(shù),直接把數(shù)組的數(shù)字元素內(nèi)容作為 key 返回return dat; },(idx,dat) -> {// 構(gòu)造 valuereturn { "index": idx, "value": dat }; });// result = { // "1": { "index": 0, "value": 1 }, // "2": { "index": 1, "value": 2 }, // "3": { "index": 2, "value": 3 }, // "4": { "index": 3, "value": 4 }, // "5": { "index": 4, "value": 5 } // }
    • map2list(dataMap, convert):將List轉(zhuǎn)換為Map,convert是轉(zhuǎn)換函數(shù)。

      // 不指定轉(zhuǎn)換函數(shù) var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2list(data); // result = [ // { "key": "key1", "value": 1}, // { "key": "key2", "value": 2}, // { "key": "key3", "value": 3} // ]// 指定轉(zhuǎn)換函數(shù) var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2list(data, (key,value) -> {return { "k" : key, "v" : value }; }); // result = [ // { "k": "key1", "v": 1}, // { "k": "key2", "v": 2}, // { "k": "key3", "v": 3} // ]
    • map2string(dataMap, joinStr, convert):將Map轉(zhuǎn)換成字符串,通常在生成Url參數(shù)時(shí)用到,joinStr表示連接符。

      var data = {"key1":1, "key2":2, "key3":3 }; var result = collect.map2string(data,"&",(key,value) -> {return key + "=" + value; }); // result = "key1=1&key2=2&key 3=3"
    • mapSort(dataMap, sortUdf):DataQL中的Map是有序的,因此可以排序。

    • listSort(dataList, sortUdf):對(duì)List進(jìn)行排序

    • groupBy(dataList, groupByKey):根據(jù)公共字段對(duì)數(shù)據(jù)進(jìn)行分組。groupByKey是String是要分組的字段名。數(shù)據(jù)集中需要有一個(gè)公共字段。

    • uniqueBy(dataList, uniqueByKey):根據(jù)公共字段去重,只返回第一次出現(xiàn)的。數(shù)據(jù)集中需要有一個(gè)公共字段。

    時(shí)間日歷函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.DateTimeUdfSource' as time;

    • now:返回當(dāng)前時(shí)間戳
    • year(time):返回時(shí)間戳中的年份,獲取當(dāng)前年份:time.year(time.now())
    • month(time):返回時(shí)間戳中的月份。
    • day、dayOfMonth:返回時(shí)間戳中的日期是這個(gè)月的第幾天。
    • hour
    • minute
    • second
    • dayOfYear(time):返回時(shí)間戳中的日期是全年的第幾天。
    • dayOfWeek(time):返回時(shí)間戳中的日期是這周的第幾天,SUNDAY=1。
    • format(time, pattern):對(duì)時(shí)間戳進(jìn)行時(shí)間日期格式化,底層使用的是java.text.SimpleDateFormat
    • parser(time, pattern):對(duì)時(shí)間按照格式進(jìn)行解析,解析為時(shí)間戳。
    Json函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.JsonUdfSource' as json;

    • toJson(target):返回String,把對(duì)象JSON序列化。
    • toFmtJson(target):返回String,把對(duì)象JSON序列化(帶格式)。
    • fromJson(jsonString):把JSON格式的字符串解析成對(duì)象。
    字符串函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.StringUdfSource' as string;

    • startsWith(str, prifix):是否以xxx開頭
    • startsWithIgnoreCase
    • endsWith(str, prifix):是否以xxx結(jié)尾
    • endsWithIgnoreCase
    • lineToHump(str):下劃線轉(zhuǎn)駝峰
    • humpToLine
    • firstCharToUpperCase(str):首字母大寫
    • firstCharToLowerCase
    • toUpperCase
    • toLowerCase
    • indexOf(str, searchStr):查找第一次出現(xiàn)的位置
    • indexOfWithStart(str, searchStr, startPos):從某一位置開始,查找之后第一次出現(xiàn)的位置
    • indexOfIgnoreCase
    • indexOfIgnoreCaseWithStart
    • lastIndexOf
    • lastIndexOfWithStart
    • lastIndexOfIgnoreCase
    • lastIndexOfIgnoreCaseWithStart
    • contains(str, searchStr):是否包含字符串。
    • containsIgnoreCase
    • containsAny(str, searchStrArray):是否包含,指定List中的值。
    • containsAnyIgnoreCase
    • trim
    • sub(str, start, end):獲取指定位置的子串。
    • left(str, len):獲取最左邊的指定長度的串。
    • right
    • alignRight:右對(duì)齊,不足的向右填充
    • alignLeft
    • alignCenter
    • compareString:比較兩個(gè)字符串大小
    • compareStringIgnoreCase
    • split
    • join(array, separator):用separator將array拼裝成字符串
    • isEmpty
    • equalsIgnoreCase
    狀態(tài)函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.basic.StateUdfSource' as state;

    • decNumber(initValue):返回一個(gè) Udf,每次調(diào)用這個(gè) UDF,都會(huì)返回一個(gè) Number。Number 值較上一次會(huì)自增 1。
    • incNumber(initValue):返回一個(gè) Udf,每次調(diào)用這個(gè) UDF,都會(huì)返回一個(gè) Number。Number 值較上一次會(huì)自減 1。
    • uuid():返回一個(gè)完整格式的UUID字符串
    • uuidToShort():返回一個(gè)不含’-'的UUID字符串
    Web函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.web.WebUdfSource' as webData;

    • cookieMap
    • cookieArrayMap
    • getCookie
    • getCookieArray
    • tempCookie
    • tempCookieAll
    • storeCookie
    • removeCookie
    • headerMap
    • headerArrayMap
    • getHeader
    • getHeaderArray
    • setHeaderAll
    • addHeader
    • addHeaderAll
    • sessionKeys
    • getSession
    • setSession
    • removeSession
    • cleanSession
    • sessionInvalidate
    • sessionId
    • sessionLastAccessedTime
    簽名/編碼函數(shù)庫

    引入函數(shù)庫:import 'net.hasor.dataql.fx.encryt.CodecUdfSource' as codec;

    • encodeString
    • decodeString
    • encodeBytes
    • decodeBytes
    • urlEncode
    • urlEncodeBy
    • urlDecode
    • urlDecodeBy
    • digestBytes
    • digestString
    • hmacBytes
    • hmacString

    總結(jié)

    以上是生活随笔為你收集整理的DataQL的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。