├── .eslintrc
├── .gitignore
├── README-CN.md
├── README.md
├── asset
├── codemirror.css
├── codemirror.js
├── qone.ico
├── qone.png
├── show-hint.js
├── sql-hint.js
└── sql-qone.js
├── index.html
├── package.json
├── qone.js
├── qone.min.js
└── test
├── clone.html
├── index.html
├── index.ie.html
├── lib
├── qunit.css
└── qunit.js
├── test.ie.js
└── test.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "standard",
3 | "rules": {
4 | "indent": [
5 | "error",
6 | 4
7 | ],
8 | "space-before-function-paren": [
9 | "error",
10 | "never"
11 | ],
12 | "one-var": 0,
13 | "no-undef": 0,
14 | "eqeqeq": 0,
15 | "no-mixed-operators": 0,
16 | "camelcase": 0,
17 | "no-return-assign": 0
18 | }
19 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 | [English](./README.md) | 简体中文
2 |
3 |
4 | ==============================
5 | [](https://www.npmjs.com/package/qone)
6 |
7 | .NET LINQ 在 javascript 中的实现
8 |
9 | ## 缘由
10 |
11 | 最近刚好修改了腾讯文档 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下面的脚本怎么转成 javascript 运行?
12 |
13 | ``` js
14 | = IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 是 foo", "A2 不是 foo")
15 | ```
16 |
17 | 公式或一些脚本语言的实现包含几个主要步骤:
18 |
19 | scanner > lexer > parser > ast > code string
20 |
21 | 得到 code string 之后可以动态运行,比如 js 里使用 eval ,eval 能保留上下文信息,缺点是执行代码包含编译器代码,eval 的安全性等。
22 | 得到 code string 之后也可直接使用生成的 code string 运行,缺点是依赖构建工具或者编辑器插件去动态替换源代码。
23 |
24 | 比如 wind 同时支持 JIT 和 AOT, qone 的思路和上面类似,但不完全相同, qone 的如下:
25 |
26 | scanner > lexer > parser > ast > method(ast)
27 |
28 | 这个后面写原理时候再细说。
29 |
30 | 总的来说,因为腾讯文档公式相关工作、早年的 kmdjs 开发 (uglify2) 和 .NET 开发,所以有了 qone 。
31 |
32 | - [LINQ](#linq)
33 | - [qone 安装](#qone-安装)
34 | - [qone 关键字与运算符](#qone-关键字与运算符)
35 | - [qone 方法注入](#qone-方法注入)
36 | - [qone select 输出](#qone-select-输出)
37 | - [qone orderby](#qone-orderby)
38 | - [qone groupby](#qone-groupby)
39 | - [qone 多数据源](#qone-多数据源)
40 | - [qone 嵌套子数据源](#qone-嵌套子数据源)
41 | - [qone limit 与分页查询](#qone-limit-与分页查询)
42 | - [links](#star--fork--pr--repl--follow-me)
43 | ---
44 |
45 | ## LINQ
46 |
47 | LINQ (语言集成查询) 是 .NET Framework 3.5 版中引入的一项创新功能。在 Visual Studio 中,可以用 Visual Basic 或 C# 为以下数据源编写 LINQ 查询:SQL Server 数据库、XML 文档、ADO.NET 数据集,以及可枚举的 Objects(即 LINQ to Objects)。
48 |
49 | qone 是一款让 Web 前端工程师在 javascript 使用 .NET 平台下类似 LINQ 语法的前端库。qone 让 Web 前端工程师通过字符串的形式实现了 LINQ to Objects 的调用(下面统一叫做 qone to objects),Objects即 JSON 组成的 Array。举个简单的例子(qone 远比下面的例子强大):
50 |
51 | ``` js
52 | var list = [
53 | { name: 'qone', age: 1 },
54 | { name: 'linq', age: 18 },
55 | { name: 'dntzhang', age: 28 }
56 | ]
57 |
58 | var result = qone({ list }).query(`
59 | from n in list
60 | where n.age > 18
61 | select n
62 | `)
63 |
64 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
65 | ```
66 |
67 | 与 LINQ 一样,和 SQL 不同,qone 的 from 也在前面,为后面语句能够有智能提示,qone 是基于 string 的实时编译,不是 javasript 的原生语法,所以虽然 from 写在前面但不支持智能提示,但可以专门为 qone 写个编辑器插件去实现智能提示,所以 qone 语法设计上依然把 from 放在前面。
68 |
69 | 从根本上说,qone to objects 表示一种新的处理集合的方法。 采用旧方法,您必须编写指定如何从集合检索数据的复杂的 foreach 循环。 而采用 qone 方法,您只需编写描述要检索的内容的声明性代码。
70 | 另外,与传统的 foreach 循环相比,qone 查询具有三大优势:
71 |
72 | * 它们更简明、更易读,尤其在筛选多个条件时
73 | * 它们使用最少的应用程序代码提供强大的筛选、排序和分组功能
74 | * 无需修改或只需做很小的修改即可将它们移植到其他数据源
75 |
76 | 通常,您要对数据执行的操作越复杂,就越能体会到 qone 相较于传统迭代技术的优势。
77 |
78 | ## qone 安装
79 |
80 | ``` bash
81 | npm install qone
82 | ```
83 |
84 | CDN:
85 |
86 | * [https://unpkg.com/qone@1.0.0/qone.js](https://unpkg.com/qone@1.0.0/qone.js)
87 | * [https://unpkg.com/qone@1.0.0/qone.min.js](https://unpkg.com/qone@1.0.0/qone.min.js)
88 |
89 | ## qone 关键字与运算符
90 |
91 | * from
92 | * in
93 | * where
94 | * select
95 | * orderby
96 | * desc
97 | * asc
98 | * groupby
99 | * limit
100 |
101 | 其中 from 和 in 一起使用,orderby 和 desc 或者 asc 一起使用。
102 |
103 | from 也可以把子属性作为 dataSource:
104 |
105 | ``` js
106 | from n in data.list
107 | ```
108 |
109 | qone 支持下面三类运算符:
110 |
111 | * 括号:( )
112 | * 比较运算符: = , > , < , >= , <= , !=
113 | * 与或非: && , || , !
114 |
115 | 条件判断语句也支持 null, undefined, true, false。
116 |
117 | 通过上面各种组合,你可以写出很复杂的查询条件。比如:
118 |
119 | ``` js
120 | qone({ list }).query(`
121 | from n in list
122 | where !(n.age > 17 || n.age < 2) && n.name != 'dntzhang'
123 | select n
124 | `)
125 | ```
126 |
127 | 也支持 bool 类型的查询:
128 |
129 | ``` js
130 | var list = [
131 | { name: 'qone', age: 1, isBaby: true },
132 | { name: 'linq', age: 18 },
133 | { name: 'dntzhang', age: 28 }]
134 |
135 | var result = qone({ list }).query(`
136 | from a in list
137 | where a.isBaby && n.name = 'qone'
138 | select a
139 | `)
140 |
141 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
142 | ```
143 |
144 | 其中 isBaby 是 bool 类型,同样的写法:
145 | a.isBaby = true (等同于: a.isBaby)
146 | a.isBaby = false (等同于: !a.isBaby)
147 |
148 | ## qone 方法注入
149 |
150 | 通过上面介绍发现 qone 不支持加减乘除位求模运算?怎么才能图灵完备?方法注入搞定一切!如下所示:
151 |
152 | ``` js
153 | QUnit.test("Method test 8", function (assert) {
154 | var arr = [1, 2, 3, 4, 5]
155 |
156 | qone('square', function (num) {
157 | return num * num
158 | })
159 |
160 | qone('sqrt', function (num) {
161 | return Math.sqrt(num)
162 | })
163 |
164 | var result = qone({ arr }).query(`
165 | from n in arr
166 | where sqrt(n) >= 2
167 | select { squareValue : square(n) }
168 | `)
169 |
170 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
171 | })
172 | ```
173 |
174 | 方法也是支持多参数传入,所以可以写出任意的查询条件。其中select, where, orderby, groupby 语句都支持方法注入。
175 |
176 | ## qone select 输出
177 |
178 | 通过 select 可以输出各种格式和字段的数据:
179 |
180 | ``` js
181 | QUnit.test("Select JSON test", function (assert) {
182 | var list = [
183 | { name: 'qone', age: 1 },
184 | { name: 'linq', age: 18 },
185 | { name: 'dntzhang', age: 28 }
186 | ]
187 |
188 | var result = qone({ list }).query(`
189 | from n in list
190 | where n.age < 20
191 | select {n.age, n.name}
192 | `)
193 |
194 | assert.deepEqual(result, [
195 | { "age": 1 , "name": "qone" },
196 | { "age": 18, "name": "linq" }
197 | ])
198 |
199 | })
200 | ```
201 |
202 | 把所有场景列举一下:
203 |
204 | * `select n` 输出源 item
205 | * `select n.name` 输出一维表
206 | * `select n.name, n.age` 输出二维表
207 | * `select { n.age, n.name }` 缺省方式输出 JSON Array(key自动使用 age 和 name)
208 | * `select { a: n.age, b: n.name }` 指定 key 输出 JSON Array
209 | * `select { a: methodName(n.age), b: n.name }` 注入方法
210 | * `select methodName(n.age), n.name` 注入方法
211 | * `select methodName(n.age, n.name, 1, true, 'abc')` 注入方法并传递参数
212 |
213 |
214 | ## qone orderby
215 |
216 |
217 | ``` js
218 | var result = qone({ list }).query(`
219 | from n in list
220 | where n.age > 0
221 | orderby n.age asc, n.name desc
222 | select n
223 | `)
224 |
225 | ```
226 |
227 | 如果没有标记 asc 或者 desc,使用默认排序 asc。
228 |
229 | ## qone groupby
230 |
231 | ``` js
232 | QUnit.test("Simple groupby test 1", function (assert) {
233 | var list = [
234 | { name: 'qone', age: 1 },
235 | { name: 'linq', age: 18 },
236 | { name: 'dntzhang1', age: 28 },
237 | { name: 'dntzhang2', age: 28 },
238 | { name: 'dntzhang3', age: 29 }
239 | ]
240 |
241 | var result = qone({ list }).query(`
242 | from n in list
243 | where n.age > 18
244 | groupby n.age
245 | `)
246 |
247 | assert.deepEqual(result, [
248 | [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],
249 | [{ "name": "dntzhang3", "age": 29 }]])
250 |
251 | })
252 | ```
253 |
254 | groupby 可以作为结束语句,不用跟着也不能跟着 select 语句,groupby 也可以支持方法注入。
255 |
256 | ## qone 多数据源
257 |
258 | ``` js
259 | QUnit.test("Multi datasource with props condition", function (assert) {
260 |
261 | var listA = [
262 | { name: 'qone', age: 1 },
263 | { name: 'linq', age: 18 },
264 | { name: 'dntzhang', age: 28 }]
265 |
266 |
267 | var listB = [
268 | { name: 'x', age: 11 },
269 | { name: 'xx', age: 18 },
270 | { name: 'xxx', age: 13 }
271 | ]
272 |
273 | var result = qone({ listA, listB }).query(`
274 | from a in listA
275 | from b in listB
276 | where a.age = b.age
277 | select a, b
278 | `)
279 |
280 | assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
281 | })
282 | ```
283 |
284 | 多数据源会产生笛卡儿积。
285 |
286 | ## qone 嵌套子数据源
287 |
288 | ``` js
289 | QUnit.test("Multi deep from test ", function (assert) {
290 |
291 | var list = [
292 | { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
293 | { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
294 | { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]
295 |
296 | var result = qone({ list }).query(`
297 | from a in list
298 | from c in a.colors
299 | from d in c.xx
300 | where d === 100
301 | select a.name, c,d
302 | `)
303 |
304 | assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
305 | })
306 | ```
307 |
308 | 也可以和自身的数据源会产生笛卡儿积。
309 |
310 | ## qone limit 与分页查询
311 |
312 | 通过 limit 可以应付最常见的两种查询场景 - top N 和 分页。
313 |
314 | 查询top3:
315 |
316 | ``` js
317 | QUnit.test("Limit top 3", function (assert) {
318 | var list = [
319 | { name: 'dntzhang1', age: 1 },
320 | { name: 'dntzhang2', age: 2 },
321 | { name: 'dntzhang3', age: 3 },
322 | { name: 'dntzhang4', age: 4 },
323 | { name: 'dntzhang5', age: 5 },
324 | { name: 'dntzhang6', age: 6 },
325 | { name: 'dntzhang7', age: 7 },
326 | { name: 'dntzhang8', age: 8 },
327 | { name: 'dntzhang9', age: 9 },
328 | { name: 'dntzhang10', age: 10 }
329 | ]
330 |
331 | var pageIndex = 1,
332 | pageSize = 4
333 | var result = qone({ list }).query(`
334 | from n in list
335 | select n
336 | limit 0, 3
337 | `)
338 |
339 |
340 | assert.deepEqual(result, [
341 |
342 | { name: 'dntzhang1', age: 1 },
343 | { name: 'dntzhang2', age: 2 },
344 | { name: 'dntzhang3', age: 3 }
345 | ])
346 |
347 | })
348 | ```
349 |
350 | 分页查询:
351 |
352 | ``` js
353 | QUnit.test("Limit one page test", function (assert) {
354 | var list = [
355 | { name: 'dntzhang1', age: 1 },
356 | { name: 'dntzhang2', age: 2 },
357 | { name: 'dntzhang3', age: 3 },
358 | { name: 'dntzhang4', age: 4 },
359 | { name: 'dntzhang5', age: 5 },
360 | { name: 'dntzhang6', age: 6 },
361 | { name: 'dntzhang7', age: 7 },
362 | { name: 'dntzhang8', age: 8 },
363 | { name: 'dntzhang9', age: 9 },
364 | { name: 'dntzhang10', age: 10 }
365 | ]
366 |
367 | var pageIndex = 1,
368 | pageSize = 4
369 | var result = qone({ list }).query(`
370 | from n in list
371 | where n.age > 0
372 | select n
373 | limit ${pageIndex * pageSize}, ${pageSize}
374 | `)
375 |
376 |
377 | assert.deepEqual(result, [
378 | { name: 'dntzhang5', age: 5 },
379 | { name: 'dntzhang6', age: 6 },
380 | { name: 'dntzhang7', age: 7 },
381 | { name: 'dntzhang8', age: 8 }])
382 |
383 | })
384 | ```
385 |
386 | ## star & fork & pr & repl & follow me
387 |
388 | * [https://github.com/dntzhang/qone](https://github.com/dntzhang/qone)
389 | * [https://dntzhang.github.io/qone](https://dntzhang.github.io/qone)
390 | * [https://github.com/dntzhang](https://github.com/dntzhang)
391 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | English | [简体中文](./README-CN.md)
3 |
4 |
5 |
6 | ==============================
7 | [](https://www.npmjs.com/package/qone)
8 |
9 | .NET LINQ in javascript
10 |
11 |
12 | ## The reason
13 |
14 | Recently, it has just changed some bug of the Excel formula of the Tencent document, mainly modifying the parser of the formula.
15 |
16 | For example, how can the following script be transformed to JavaScript?
17 |
18 | ``` js
19 | = IF(SUM(J6:J7) + SUM(J6:J7) > 10, "A2 is foo", "A2 is not foo")
20 | ```
21 |
22 | The implementation of formulas or scripting languages includes several main steps:
23 |
24 | Scanner > lexer > parser > ast > code string
25 |
26 | After getting code string, you can run (JIT) dynamically, such as using Eval in JS, Eval can retain context information, the disadvantage is that the execution code contains compiler code, and it is unsafe, and so on.
27 | After getting code string, you can also use the generated code string to run (AOT) directly, and the disadvantage is to rely on the build tool or editor plug-in to dynamically replace the source code.
28 |
29 | For example, wind supports JIT and AOT at the same time. Qone's thinking is similar to that above, but not exactly the same. Qone is as follows:
30 |
31 | Scanner > lexer > parser > ast > method(ast)
32 |
33 | The detailed principles will be written later. In general, the reasons are the work of the Tencent document formula, early kmdjs development (uglify2) and.NET development, so there is Qone.
34 |
35 | - [LINQ](#linq)
36 | - [qone install](#qone-install)
37 | - [qone keyword and operator](#qone-keyword-and-operator)
38 | - [qone method](#qone-method)
39 | - [qone select](#qone-select)
40 | - [qone orderby](#qone-orderby)
41 | - [qone groupby](#qone-groupby)
42 | - [qone multiple data source](#qone-multiple-data-source)
43 | - [qone subdata source](#qone-subdata-source)
44 | - [qone limit and pagination](#qone-limit-and-pagination)
45 | - [links](#star--fork--pr--repl--follow-me)
46 | ---
47 |
48 | ## LINQ
49 |
50 | LINQ (language integrated query) is an innovative function introduced in.NET Framework 3.5. In Visual Studio, you can write LINQ queries with Visual Basic or C# for the following data sources: the SQL Server database, XML document, ADO.NET data set, and enumerable Objects.
51 |
52 | Qone allows Web front-end engineers to use LINQ to Objects through js string or js template string, Objects is an array of JSON. Let me give you a simple example (Qone is much stronger than the following example):
53 |
54 |
55 | ``` js
56 | var list = [
57 | { name: 'qone', age: 1 },
58 | { name: 'linq', age: 18 },
59 | { name: 'dntzhang', age: 28 }
60 | ]
61 |
62 | var result = qone({ list }).query(`
63 | from n in list
64 | where n.age > 18
65 | select n
66 | `)
67 |
68 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
69 | ```
70 |
71 | Qone's `from` keyword is also in front like LINQ, with intelligent prompts for the later statements,but qone is real-time compilation based on string, not the native syntax of javasript, so although from is written in the front but does not support intelligent hints.
72 |
73 | ## qone install
74 |
75 | ``` bash
76 | npm install qone
77 | ```
78 |
79 | or get it by CDN:
80 |
81 | * [https://unpkg.com/qone@1.0.0/qone.js](https://unpkg.com/qone@1.0.0/qone.js)
82 | * [https://unpkg.com/qone@1.0.0/qone.min.js](https://unpkg.com/qone@1.0.0/qone.min.js)
83 |
84 | ## qone keyword and operator
85 |
86 | * from
87 | * in
88 | * where
89 | * select
90 | * orderby
91 | * desc
92 | * asc
93 | * groupby
94 | * limit
95 |
96 | from and in are used together, orderby and desc or asc are used together.
97 |
98 | from can also take the sub attributes as dataSource:
99 |
100 | ``` js
101 | from n in data.list
102 | ```
103 |
104 | Qone supports the following three class operators:
105 |
106 | * brackets:( )
107 | * comparison operator: = , > , < , >= , <= , !=
108 | * and or not: && , || , !
109 |
110 | Conditional judgement also supports null, undefined, true, false.
111 |
112 | Through the above combinations, you can write complex query conditions. For example:
113 |
114 | ``` js
115 | qone({ list }).query(`
116 | from n in list
117 | where !(n.age > 17 || n.age < 2) && n.name != 'dntzhang'
118 | select n
119 | `)
120 | ```
121 |
122 | The bool type of query is also supported:
123 |
124 | ``` js
125 | var list = [
126 | { name: 'qone', age: 1, isBaby: true },
127 | { name: 'linq', age: 18 },
128 | { name: 'dntzhang', age: 28 }]
129 |
130 | var result = qone({ list }).query(`
131 | from a in list
132 | where a.isBaby && n.name = 'qone'
133 | select a
134 | `)
135 |
136 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
137 | ```
138 |
139 | isBaby is the bool type, and the same way:
140 | a.isBaby = true (equivalent to: a.isBaby)
141 | a.isBaby = false (equivalent to: !a.isBaby)
142 |
143 | ## qone method
144 |
145 | From the above, it is found that QOne does not support arithmetic operations of addition, subtraction, multiplication and division. How can be turing-complete ? Method injection to do everything! As shown below:
146 |
147 | ``` js
148 | QUnit.test("Method test 8", function (assert) {
149 | var arr = [1, 2, 3, 4, 5]
150 |
151 | qone('square', function (num) {
152 | return num * num
153 | })
154 |
155 | qone('sqrt', function (num) {
156 | return Math.sqrt(num)
157 | })
158 |
159 | var result = qone({ arr }).query(`
160 | from n in arr
161 | where sqrt(n) >= 2
162 | select { squareValue : square(n) }
163 | `)
164 |
165 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
166 | })
167 | ```
168 |
169 | The method also supports the introduction of multiple parameters, so it can write arbitrary query conditions. select, where, orderby, groupby statements support method injection.
170 |
171 | ## qone select
172 |
173 | select can output data of various formats and fields:
174 |
175 | ``` js
176 | QUnit.test("Select JSON test", function (assert) {
177 | var list = [
178 | { name: 'qone', age: 1 },
179 | { name: 'linq', age: 18 },
180 | { name: 'dntzhang', age: 28 }
181 | ]
182 |
183 | var result = qone({ list }).query(`
184 | from n in list
185 | where n.age < 20
186 | select {n.age, n.name}
187 | `)
188 |
189 | assert.deepEqual(result, [
190 | { "age": 1 , "name": "qone" },
191 | { "age": 18, "name": "linq" }
192 | ])
193 |
194 | })
195 | ```
196 |
197 | List all the scenes:
198 |
199 | * `select n` Output source item
200 | * `select n.name` Output one-dimensional table
201 | * `select n.name, n.age` Output two-dimensional table
202 | * `select { n.age, n.name }` Output JSON Array by default (key automatically uses age and name).
203 | * `select { a: n.age, b: n.name }` Specify the key output JSON Array
204 | * `select { a: methodName(n.age), b: n.name }` Injection method
205 | * `select methodName(n.age), n.name` Injection method
206 | * `select methodName(n.age, n.name, 1, true, 'abc')` Injection method and transfer parameters
207 |
208 |
209 |
210 | ## qone orderby
211 |
212 |
213 | ``` js
214 | var result = qone({ list }).query(`
215 | from n in list
216 | where n.age > 0
217 | orderby n.age asc, n.name desc
218 | select n
219 | `)
220 |
221 | ```
222 |
223 | If no asc or desc is marked, use the default sort asc.
224 |
225 | ## qone groupby
226 |
227 | ``` js
228 | QUnit.test("Simple groupby test 1", function (assert) {
229 | var list = [
230 | { name: 'qone', age: 1 },
231 | { name: 'linq', age: 18 },
232 | { name: 'dntzhang1', age: 28 },
233 | { name: 'dntzhang2', age: 28 },
234 | { name: 'dntzhang3', age: 29 }
235 | ]
236 |
237 | var result = qone({ list }).query(`
238 | from n in list
239 | where n.age > 18
240 | groupby n.age
241 | `)
242 |
243 | assert.deepEqual(result, [
244 | [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],
245 | [{ "name": "dntzhang3", "age": 29 }]])
246 |
247 | })
248 | ```
249 |
250 | groupby can be used as an ending statement, without following or following select statements. groupby can also support method injection.
251 |
252 | ## qone multiple data source
253 |
254 | ``` js
255 | QUnit.test("Multi datasource with props condition", function (assert) {
256 |
257 | var listA = [
258 | { name: 'qone', age: 1 },
259 | { name: 'linq', age: 18 },
260 | { name: 'dntzhang', age: 28 }]
261 |
262 |
263 | var listB = [
264 | { name: 'x', age: 11 },
265 | { name: 'xx', age: 18 },
266 | { name: 'xxx', age: 13 }
267 | ]
268 |
269 | var result = qone({ listA, listB }).query(`
270 | from a in listA
271 | from b in listB
272 | where a.age = b.age
273 | select a, b
274 | `)
275 |
276 | assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
277 | })
278 | ```
279 |
280 | The multi data source produces Cartesian product.
281 |
282 | ## qone subdata source
283 |
284 | ``` js
285 | QUnit.test("Multi deep from test ", function (assert) {
286 |
287 | var list = [
288 | { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
289 | { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
290 | { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]
291 |
292 | var result = qone({ list }).query(`
293 | from a in list
294 | from c in a.colors
295 | from d in c.xx
296 | where d === 100
297 | select a.name, c,d
298 | `)
299 |
300 | assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
301 | })
302 | ```
303 |
304 | It can also produce Cartesian product with its own data source.
305 |
306 | ## qone limit and pagination
307 |
308 | Limit can cope with the two most common query scenarios - top N and paging.
309 |
310 | Query top3:
311 |
312 | ``` js
313 | QUnit.test("Limit top 3", function (assert) {
314 | var list = [
315 | { name: 'dntzhang1', age: 1 },
316 | { name: 'dntzhang2', age: 2 },
317 | { name: 'dntzhang3', age: 3 },
318 | { name: 'dntzhang4', age: 4 },
319 | { name: 'dntzhang5', age: 5 },
320 | { name: 'dntzhang6', age: 6 },
321 | { name: 'dntzhang7', age: 7 },
322 | { name: 'dntzhang8', age: 8 },
323 | { name: 'dntzhang9', age: 9 },
324 | { name: 'dntzhang10', age: 10 }
325 | ]
326 |
327 | var pageIndex = 1,
328 | pageSize = 4
329 | var result = qone({ list }).query(`
330 | from n in list
331 | select n
332 | limit 0, 3
333 | `)
334 |
335 |
336 | assert.deepEqual(result, [
337 |
338 | { name: 'dntzhang1', age: 1 },
339 | { name: 'dntzhang2', age: 2 },
340 | { name: 'dntzhang3', age: 3 }
341 | ])
342 |
343 | })
344 | ```
345 |
346 | Paging query:
347 |
348 | ``` js
349 | QUnit.test("Limit one page test", function (assert) {
350 | var list = [
351 | { name: 'dntzhang1', age: 1 },
352 | { name: 'dntzhang2', age: 2 },
353 | { name: 'dntzhang3', age: 3 },
354 | { name: 'dntzhang4', age: 4 },
355 | { name: 'dntzhang5', age: 5 },
356 | { name: 'dntzhang6', age: 6 },
357 | { name: 'dntzhang7', age: 7 },
358 | { name: 'dntzhang8', age: 8 },
359 | { name: 'dntzhang9', age: 9 },
360 | { name: 'dntzhang10', age: 10 }
361 | ]
362 |
363 | var pageIndex = 1,
364 | pageSize = 4
365 | var result = qone({ list }).query(`
366 | from n in list
367 | where n.age > 0
368 | select n
369 | limit ${pageIndex * pageSize}, ${pageSize}
370 | `)
371 |
372 |
373 | assert.deepEqual(result, [
374 | { name: 'dntzhang5', age: 5 },
375 | { name: 'dntzhang6', age: 6 },
376 | { name: 'dntzhang7', age: 7 },
377 | { name: 'dntzhang8', age: 8 }])
378 |
379 | })
380 | ```
381 |
382 | ## star & fork & pr & repl & follow me
383 |
384 | * [https://github.com/dntzhang/qone](https://github.com/dntzhang/qone)
385 | * [https://dntzhang.github.io/qone](https://dntzhang.github.io/qone)
386 | * [https://github.com/dntzhang](https://github.com/dntzhang)
387 |
--------------------------------------------------------------------------------
/asset/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | direction: ltr;
9 | }
10 |
11 | /* PADDING */
12 |
13 | .CodeMirror-lines {
14 | padding: 4px 0; /* Vertical padding around content */
15 | }
16 | .CodeMirror pre {
17 | padding: 0 4px; /* Horizontal padding of content */
18 | }
19 |
20 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
21 | background-color: white; /* The little square between H and V scrollbars */
22 | }
23 |
24 | /* GUTTER */
25 |
26 | .CodeMirror-gutters {
27 | border-right: 1px solid #ddd;
28 | background-color: #f7f7f7;
29 | white-space: nowrap;
30 | }
31 | .CodeMirror-linenumbers {}
32 | .CodeMirror-linenumber {
33 | padding: 0 3px 0 5px;
34 | min-width: 20px;
35 | text-align: right;
36 | color: #999;
37 | white-space: nowrap;
38 | }
39 |
40 | .CodeMirror-guttermarker { color: black; }
41 | .CodeMirror-guttermarker-subtle { color: #999; }
42 |
43 | /* CURSOR */
44 |
45 | .CodeMirror-cursor {
46 | border-left: 1px solid black;
47 | border-right: none;
48 | width: 0;
49 | }
50 | /* Shown when moving in bi-directional text */
51 | .CodeMirror div.CodeMirror-secondarycursor {
52 | border-left: 1px solid silver;
53 | }
54 | .cm-fat-cursor .CodeMirror-cursor {
55 | width: auto;
56 | border: 0 !important;
57 | background: #7e7;
58 | }
59 | .cm-fat-cursor div.CodeMirror-cursors {
60 | z-index: 1;
61 | }
62 | .cm-fat-cursor-mark {
63 | background-color: rgba(20, 255, 20, 0.5);
64 | -webkit-animation: blink 1.06s steps(1) infinite;
65 | -moz-animation: blink 1.06s steps(1) infinite;
66 | animation: blink 1.06s steps(1) infinite;
67 | }
68 | .cm-animate-fat-cursor {
69 | width: auto;
70 | border: 0;
71 | -webkit-animation: blink 1.06s steps(1) infinite;
72 | -moz-animation: blink 1.06s steps(1) infinite;
73 | animation: blink 1.06s steps(1) infinite;
74 | background-color: #7e7;
75 | }
76 | @-moz-keyframes blink {
77 | 0% {}
78 | 50% { background-color: transparent; }
79 | 100% {}
80 | }
81 | @-webkit-keyframes blink {
82 | 0% {}
83 | 50% { background-color: transparent; }
84 | 100% {}
85 | }
86 | @keyframes blink {
87 | 0% {}
88 | 50% { background-color: transparent; }
89 | 100% {}
90 | }
91 |
92 | /* Can style cursor different in overwrite (non-insert) mode */
93 | .CodeMirror-overwrite .CodeMirror-cursor {}
94 |
95 | .cm-tab { display: inline-block; text-decoration: inherit; }
96 |
97 | .CodeMirror-rulers {
98 | position: absolute;
99 | left: 0; right: 0; top: -50px; bottom: -20px;
100 | overflow: hidden;
101 | }
102 | .CodeMirror-ruler {
103 | border-left: 1px solid #ccc;
104 | top: 0; bottom: 0;
105 | position: absolute;
106 | }
107 |
108 | /* DEFAULT THEME */
109 |
110 | .cm-s-default .cm-header {color: blue;}
111 | .cm-s-default .cm-quote {color: #090;}
112 | .cm-negative {color: #d44;}
113 | .cm-positive {color: #292;}
114 | .cm-header, .cm-strong {font-weight: bold;}
115 | .cm-em {font-style: italic;}
116 | .cm-link {text-decoration: underline;}
117 | .cm-strikethrough {text-decoration: line-through;}
118 |
119 | .cm-s-default .cm-keyword {color: #708;}
120 | .cm-s-default .cm-atom {color: #219;}
121 | .cm-s-default .cm-number {color: #164;}
122 | .cm-s-default .cm-def {color: #00f;}
123 | .cm-s-default .cm-variable,
124 | .cm-s-default .cm-punctuation,
125 | .cm-s-default .cm-property,
126 | .cm-s-default .cm-operator {}
127 | .cm-s-default .cm-variable-2 {color: #05a;}
128 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
129 | .cm-s-default .cm-comment {color: #a50;}
130 | .cm-s-default .cm-string {color: #a11;}
131 | .cm-s-default .cm-string-2 {color: #f50;}
132 | .cm-s-default .cm-meta {color: #555;}
133 | .cm-s-default .cm-qualifier {color: #555;}
134 | .cm-s-default .cm-builtin {color: #30a;}
135 | .cm-s-default .cm-bracket {color: #997;}
136 | .cm-s-default .cm-tag {color: #170;}
137 | .cm-s-default .cm-attribute {color: #00c;}
138 | .cm-s-default .cm-hr {color: #999;}
139 | .cm-s-default .cm-link {color: #00c;}
140 |
141 | .cm-s-default .cm-error {color: #f00;}
142 | .cm-invalidchar {color: #f00;}
143 |
144 | .CodeMirror-composing { border-bottom: 2px solid; }
145 |
146 | /* Default styles for common addons */
147 |
148 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
149 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
150 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
151 | .CodeMirror-activeline-background {background: #e8f2ff;}
152 |
153 | /* STOP */
154 |
155 | /* The rest of this file contains styles related to the mechanics of
156 | the editor. You probably shouldn't touch them. */
157 |
158 | .CodeMirror {
159 | position: relative;
160 | overflow: hidden;
161 | background: white;
162 | }
163 |
164 | .CodeMirror-scroll {
165 | overflow: scroll !important; /* Things will break if this is overridden */
166 | /* 30px is the magic margin used to hide the element's real scrollbars */
167 | /* See overflow: hidden in .CodeMirror */
168 | margin-bottom: -30px; margin-right: -30px;
169 | padding-bottom: 30px;
170 | height: 100%;
171 | outline: none; /* Prevent dragging from highlighting the element */
172 | position: relative;
173 | }
174 | .CodeMirror-sizer {
175 | position: relative;
176 | border-right: 30px solid transparent;
177 | }
178 |
179 | /* The fake, visible scrollbars. Used to force redraw during scrolling
180 | before actual scrolling happens, thus preventing shaking and
181 | flickering artifacts. */
182 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
183 | position: absolute;
184 | z-index: 6;
185 | display: none;
186 | }
187 | .CodeMirror-vscrollbar {
188 | right: 0; top: 0;
189 | overflow-x: hidden;
190 | overflow-y: scroll;
191 | }
192 | .CodeMirror-hscrollbar {
193 | bottom: 0; left: 0;
194 | overflow-y: hidden;
195 | overflow-x: scroll;
196 | }
197 | .CodeMirror-scrollbar-filler {
198 | right: 0; bottom: 0;
199 | }
200 | .CodeMirror-gutter-filler {
201 | left: 0; bottom: 0;
202 | }
203 |
204 | .CodeMirror-gutters {
205 | position: absolute; left: 0; top: 0;
206 | min-height: 100%;
207 | z-index: 3;
208 | }
209 | .CodeMirror-gutter {
210 | white-space: normal;
211 | height: 100%;
212 | display: inline-block;
213 | vertical-align: top;
214 | margin-bottom: -30px;
215 | }
216 | .CodeMirror-gutter-wrapper {
217 | position: absolute;
218 | z-index: 4;
219 | background: none !important;
220 | border: none !important;
221 | }
222 | .CodeMirror-gutter-background {
223 | position: absolute;
224 | top: 0; bottom: 0;
225 | z-index: 4;
226 | }
227 | .CodeMirror-gutter-elt {
228 | position: absolute;
229 | cursor: default;
230 | z-index: 4;
231 | }
232 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
233 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
234 |
235 | .CodeMirror-lines {
236 | cursor: text;
237 | min-height: 1px; /* prevents collapsing before first draw */
238 | }
239 | .CodeMirror pre {
240 | /* Reset some styles that the rest of the page might have set */
241 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
242 | border-width: 0;
243 | background: transparent;
244 | font-family: inherit;
245 | font-size: inherit;
246 | margin: 0;
247 | white-space: pre;
248 | word-wrap: normal;
249 | line-height: inherit;
250 | color: inherit;
251 | z-index: 2;
252 | position: relative;
253 | overflow: visible;
254 | -webkit-tap-highlight-color: transparent;
255 | -webkit-font-variant-ligatures: contextual;
256 | font-variant-ligatures: contextual;
257 | }
258 | .CodeMirror-wrap pre {
259 | word-wrap: break-word;
260 | white-space: pre-wrap;
261 | word-break: normal;
262 | }
263 |
264 | .CodeMirror-linebackground {
265 | position: absolute;
266 | left: 0; right: 0; top: 0; bottom: 0;
267 | z-index: 0;
268 | }
269 |
270 | .CodeMirror-linewidget {
271 | position: relative;
272 | z-index: 2;
273 | padding: 0.1px; /* Force widget margins to stay inside of the container */
274 | }
275 |
276 | .CodeMirror-widget {}
277 |
278 | .CodeMirror-rtl pre { direction: rtl; }
279 |
280 | .CodeMirror-code {
281 | outline: none;
282 | }
283 |
284 | /* Force content-box sizing for the elements where we expect it */
285 | .CodeMirror-scroll,
286 | .CodeMirror-sizer,
287 | .CodeMirror-gutter,
288 | .CodeMirror-gutters,
289 | .CodeMirror-linenumber {
290 | -moz-box-sizing: content-box;
291 | box-sizing: content-box;
292 | }
293 |
294 | .CodeMirror-measure {
295 | position: absolute;
296 | width: 100%;
297 | height: 0;
298 | overflow: hidden;
299 | visibility: hidden;
300 | }
301 |
302 | .CodeMirror-cursor {
303 | position: absolute;
304 | pointer-events: none;
305 | }
306 | .CodeMirror-measure pre { position: static; }
307 |
308 | div.CodeMirror-cursors {
309 | visibility: hidden;
310 | position: relative;
311 | z-index: 3;
312 | }
313 | div.CodeMirror-dragcursors {
314 | visibility: visible;
315 | }
316 |
317 | .CodeMirror-focused div.CodeMirror-cursors {
318 | visibility: visible;
319 | }
320 |
321 | .CodeMirror-selected { background: #d9d9d9; }
322 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
323 | .CodeMirror-crosshair { cursor: crosshair; }
324 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
325 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
326 |
327 | .cm-searching {
328 | background-color: #ffa;
329 | background-color: rgba(255, 255, 0, .4);
330 | }
331 |
332 | /* Used to force a border model for a node */
333 | .cm-force-border { padding-right: .1px; }
334 |
335 | @media print {
336 | /* Hide the cursor when printing */
337 | .CodeMirror div.CodeMirror-cursors {
338 | visibility: hidden;
339 | }
340 | }
341 |
342 | /* See issue #2901 */
343 | .cm-tab-wrap-hack:after { content: ''; }
344 |
345 | /* Help users use markselection to safely style text background */
346 | span.CodeMirror-selectedtext { background: none; }
347 |
--------------------------------------------------------------------------------
/asset/qone.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dntzhang/qone/5c6dab86edb09a15d163796b43c0ea1f293f9dd6/asset/qone.ico
--------------------------------------------------------------------------------
/asset/qone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dntzhang/qone/5c6dab86edb09a15d163796b43c0ea1f293f9dd6/asset/qone.png
--------------------------------------------------------------------------------
/asset/show-hint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var HINT_ELEMENT_CLASS = "CodeMirror-hint";
15 | var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
16 |
17 | // This is the old interface, kept around for now to stay
18 | // backwards-compatible.
19 | CodeMirror.showHint = function(cm, getHints, options) {
20 | if (!getHints) return cm.showHint(options);
21 | if (options && options.async) getHints.async = true;
22 | var newOpts = {hint: getHints};
23 | if (options) for (var prop in options) newOpts[prop] = options[prop];
24 | return cm.showHint(newOpts);
25 | };
26 |
27 | CodeMirror.defineExtension("showHint", function(options) {
28 | options = parseOptions(this, this.getCursor("start"), options);
29 | var selections = this.listSelections()
30 | if (selections.length > 1) return;
31 | // By default, don't allow completion when something is selected.
32 | // A hint function can have a `supportsSelection` property to
33 | // indicate that it can handle selections.
34 | if (this.somethingSelected()) {
35 | if (!options.hint.supportsSelection) return;
36 | // Don't try with cross-line selections
37 | for (var i = 0; i < selections.length; i++)
38 | if (selections[i].head.line != selections[i].anchor.line) return;
39 | }
40 |
41 | if (this.state.completionActive) this.state.completionActive.close();
42 | var completion = this.state.completionActive = new Completion(this, options);
43 | if (!completion.options.hint) return;
44 |
45 | CodeMirror.signal(this, "startCompletion", this);
46 | completion.update(true);
47 | });
48 |
49 | function Completion(cm, options) {
50 | this.cm = cm;
51 | this.options = options;
52 | this.widget = null;
53 | this.debounce = 0;
54 | this.tick = 0;
55 | this.startPos = this.cm.getCursor("start");
56 | this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;
57 |
58 | var self = this;
59 | cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
60 | }
61 |
62 | var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
63 | return setTimeout(fn, 1000/60);
64 | };
65 | var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
66 |
67 | Completion.prototype = {
68 | close: function() {
69 | if (!this.active()) return;
70 | this.cm.state.completionActive = null;
71 | this.tick = null;
72 | this.cm.off("cursorActivity", this.activityFunc);
73 |
74 | if (this.widget && this.data) CodeMirror.signal(this.data, "close");
75 | if (this.widget) this.widget.close();
76 | CodeMirror.signal(this.cm, "endCompletion", this.cm);
77 | },
78 |
79 | active: function() {
80 | return this.cm.state.completionActive == this;
81 | },
82 |
83 | pick: function(data, i) {
84 | var completion = data.list[i];
85 | if (completion.hint) completion.hint(this.cm, data, completion);
86 | else this.cm.replaceRange(getText(completion), completion.from || data.from,
87 | completion.to || data.to, "complete");
88 | CodeMirror.signal(data, "pick", completion);
89 | this.close();
90 | },
91 |
92 | cursorActivity: function() {
93 | if (this.debounce) {
94 | cancelAnimationFrame(this.debounce);
95 | this.debounce = 0;
96 | }
97 |
98 | var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
99 | if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
100 | pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
101 | (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
102 | this.close();
103 | } else {
104 | var self = this;
105 | this.debounce = requestAnimationFrame(function() {self.update();});
106 | if (this.widget) this.widget.disable();
107 | }
108 | },
109 |
110 | update: function(first) {
111 | if (this.tick == null) return
112 | var self = this, myTick = ++this.tick
113 | fetchHints(this.options.hint, this.cm, this.options, function(data) {
114 | if (self.tick == myTick) self.finishUpdate(data, first)
115 | })
116 | },
117 |
118 | finishUpdate: function(data, first) {
119 | if (this.data) CodeMirror.signal(this.data, "update");
120 |
121 | var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
122 | if (this.widget) this.widget.close();
123 |
124 | this.data = data;
125 |
126 | if (data && data.list.length) {
127 | if (picked && data.list.length == 1) {
128 | this.pick(data, 0);
129 | } else {
130 | this.widget = new Widget(this, data);
131 | CodeMirror.signal(data, "shown");
132 | }
133 | }
134 | }
135 | };
136 |
137 | function parseOptions(cm, pos, options) {
138 | var editor = cm.options.hintOptions;
139 | var out = {};
140 | for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
141 | if (editor) for (var prop in editor)
142 | if (editor[prop] !== undefined) out[prop] = editor[prop];
143 | if (options) for (var prop in options)
144 | if (options[prop] !== undefined) out[prop] = options[prop];
145 | if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
146 | return out;
147 | }
148 |
149 | function getText(completion) {
150 | if (typeof completion == "string") return completion;
151 | else return completion.text;
152 | }
153 |
154 | function buildKeyMap(completion, handle) {
155 | var baseMap = {
156 | Up: function() {handle.moveFocus(-1);},
157 | Down: function() {handle.moveFocus(1);},
158 | PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
159 | PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
160 | Home: function() {handle.setFocus(0);},
161 | End: function() {handle.setFocus(handle.length - 1);},
162 | Enter: handle.pick,
163 | Tab: handle.pick,
164 | Esc: handle.close
165 | };
166 | var custom = completion.options.customKeys;
167 | var ourMap = custom ? {} : baseMap;
168 | function addBinding(key, val) {
169 | var bound;
170 | if (typeof val != "string")
171 | bound = function(cm) { return val(cm, handle); };
172 | // This mechanism is deprecated
173 | else if (baseMap.hasOwnProperty(val))
174 | bound = baseMap[val];
175 | else
176 | bound = val;
177 | ourMap[key] = bound;
178 | }
179 | if (custom)
180 | for (var key in custom) if (custom.hasOwnProperty(key))
181 | addBinding(key, custom[key]);
182 | var extra = completion.options.extraKeys;
183 | if (extra)
184 | for (var key in extra) if (extra.hasOwnProperty(key))
185 | addBinding(key, extra[key]);
186 | return ourMap;
187 | }
188 |
189 | function getHintElement(hintsElement, el) {
190 | while (el && el != hintsElement) {
191 | if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
192 | el = el.parentNode;
193 | }
194 | }
195 |
196 | function Widget(completion, data) {
197 | this.completion = completion;
198 | this.data = data;
199 | this.picked = false;
200 | var widget = this, cm = completion.cm;
201 |
202 | var hints = this.hints = document.createElement("ul");
203 | hints.className = "CodeMirror-hints";
204 | this.selectedHint = data.selectedHint || 0;
205 |
206 | var completions = data.list;
207 | for (var i = 0; i < completions.length; ++i) {
208 | var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
209 | var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
210 | if (cur.className != null) className = cur.className + " " + className;
211 | elt.className = className;
212 | if (cur.render) cur.render(elt, data, cur);
213 | else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
214 | elt.hintId = i;
215 | }
216 |
217 | var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
218 | var left = pos.left, top = pos.bottom, below = true;
219 | hints.style.left = left + "px";
220 | hints.style.top = top + "px";
221 | // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
222 | var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
223 | var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
224 | (completion.options.container || document.body).appendChild(hints);
225 | var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
226 | var scrolls = hints.scrollHeight > hints.clientHeight + 1
227 | var startScroll = cm.getScrollInfo();
228 |
229 | if (overlapY > 0) {
230 | var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
231 | if (curTop - height > 0) { // Fits above cursor
232 | hints.style.top = (top = pos.top - height) + "px";
233 | below = false;
234 | } else if (height > winH) {
235 | hints.style.height = (winH - 5) + "px";
236 | hints.style.top = (top = pos.bottom - box.top) + "px";
237 | var cursor = cm.getCursor();
238 | if (data.from.ch != cursor.ch) {
239 | pos = cm.cursorCoords(cursor);
240 | hints.style.left = (left = pos.left) + "px";
241 | box = hints.getBoundingClientRect();
242 | }
243 | }
244 | }
245 | var overlapX = box.right - winW;
246 | if (overlapX > 0) {
247 | if (box.right - box.left > winW) {
248 | hints.style.width = (winW - 5) + "px";
249 | overlapX -= (box.right - box.left) - winW;
250 | }
251 | hints.style.left = (left = pos.left - overlapX) + "px";
252 | }
253 | if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
254 | node.style.paddingRight = cm.display.nativeBarWidth + "px"
255 |
256 | cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
257 | moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
258 | setFocus: function(n) { widget.changeActive(n); },
259 | menuSize: function() { return widget.screenAmount(); },
260 | length: completions.length,
261 | close: function() { completion.close(); },
262 | pick: function() { widget.pick(); },
263 | data: data
264 | }));
265 |
266 | if (completion.options.closeOnUnfocus) {
267 | var closingOnBlur;
268 | cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
269 | cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
270 | }
271 |
272 | cm.on("scroll", this.onScroll = function() {
273 | var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
274 | var newTop = top + startScroll.top - curScroll.top;
275 | var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
276 | if (!below) point += hints.offsetHeight;
277 | if (point <= editor.top || point >= editor.bottom) return completion.close();
278 | hints.style.top = newTop + "px";
279 | hints.style.left = (left + startScroll.left - curScroll.left) + "px";
280 | });
281 |
282 | CodeMirror.on(hints, "dblclick", function(e) {
283 | var t = getHintElement(hints, e.target || e.srcElement);
284 | if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
285 | });
286 |
287 | CodeMirror.on(hints, "click", function(e) {
288 | var t = getHintElement(hints, e.target || e.srcElement);
289 | if (t && t.hintId != null) {
290 | widget.changeActive(t.hintId);
291 | if (completion.options.completeOnSingleClick) widget.pick();
292 | }
293 | });
294 |
295 | CodeMirror.on(hints, "mousedown", function() {
296 | setTimeout(function(){cm.focus();}, 20);
297 | });
298 |
299 | CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
300 | return true;
301 | }
302 |
303 | Widget.prototype = {
304 | close: function() {
305 | if (this.completion.widget != this) return;
306 | this.completion.widget = null;
307 | this.hints.parentNode.removeChild(this.hints);
308 | this.completion.cm.removeKeyMap(this.keyMap);
309 |
310 | var cm = this.completion.cm;
311 | if (this.completion.options.closeOnUnfocus) {
312 | cm.off("blur", this.onBlur);
313 | cm.off("focus", this.onFocus);
314 | }
315 | cm.off("scroll", this.onScroll);
316 | },
317 |
318 | disable: function() {
319 | this.completion.cm.removeKeyMap(this.keyMap);
320 | var widget = this;
321 | this.keyMap = {Enter: function() { widget.picked = true; }};
322 | this.completion.cm.addKeyMap(this.keyMap);
323 | },
324 |
325 | pick: function() {
326 | this.completion.pick(this.data, this.selectedHint);
327 | },
328 |
329 | changeActive: function(i, avoidWrap) {
330 | if (i >= this.data.list.length)
331 | i = avoidWrap ? this.data.list.length - 1 : 0;
332 | else if (i < 0)
333 | i = avoidWrap ? 0 : this.data.list.length - 1;
334 | if (this.selectedHint == i) return;
335 | var node = this.hints.childNodes[this.selectedHint];
336 | node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
337 | node = this.hints.childNodes[this.selectedHint = i];
338 | node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
339 | if (node.offsetTop < this.hints.scrollTop)
340 | this.hints.scrollTop = node.offsetTop - 3;
341 | else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
342 | this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
343 | CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
344 | },
345 |
346 | screenAmount: function() {
347 | return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
348 | }
349 | };
350 |
351 | function applicableHelpers(cm, helpers) {
352 | if (!cm.somethingSelected()) return helpers
353 | var result = []
354 | for (var i = 0; i < helpers.length; i++)
355 | if (helpers[i].supportsSelection) result.push(helpers[i])
356 | return result
357 | }
358 |
359 | function fetchHints(hint, cm, options, callback) {
360 | if (hint.async) {
361 | hint(cm, callback, options)
362 | } else {
363 | var result = hint(cm, options)
364 | if (result && result.then) result.then(callback)
365 | else callback(result)
366 | }
367 | }
368 |
369 | function resolveAutoHints(cm, pos) {
370 | var helpers = cm.getHelpers(pos, "hint"), words
371 | if (helpers.length) {
372 | var resolved = function(cm, callback, options) {
373 | var app = applicableHelpers(cm, helpers);
374 | function run(i) {
375 | if (i == app.length) return callback(null)
376 | fetchHints(app[i], cm, options, function(result) {
377 | if (result && result.list.length > 0) callback(result)
378 | else run(i + 1)
379 | })
380 | }
381 | run(0)
382 | }
383 | resolved.async = true
384 | resolved.supportsSelection = true
385 | return resolved
386 | } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
387 | return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
388 | } else if (CodeMirror.hint.anyword) {
389 | return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
390 | } else {
391 | return function() {}
392 | }
393 | }
394 |
395 | CodeMirror.registerHelper("hint", "auto", {
396 | resolve: resolveAutoHints
397 | });
398 |
399 | CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
400 | var cur = cm.getCursor(), token = cm.getTokenAt(cur)
401 | var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
402 | if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
403 | term = token.string.substr(0, cur.ch - token.start)
404 | } else {
405 | term = ""
406 | from = cur
407 | }
408 | var found = [];
409 | for (var i = 0; i < options.words.length; i++) {
410 | var word = options.words[i];
411 | if (word.slice(0, term.length) == term)
412 | found.push(word);
413 | }
414 |
415 | if (found.length) return {list: found, from: from, to: to};
416 | });
417 |
418 | CodeMirror.commands.autocomplete = CodeMirror.showHint;
419 |
420 | var defaultOptions = {
421 | hint: CodeMirror.hint.auto,
422 | completeSingle: true,
423 | alignWithWord: true,
424 | closeCharacters: /[\s()\[\]{};:>,]/,
425 | closeOnUnfocus: true,
426 | completeOnSingleClick: true,
427 | container: null,
428 | customKeys: null,
429 | extraKeys: null
430 | };
431 |
432 | CodeMirror.defineOption("hintOptions", null);
433 | });
434 |
--------------------------------------------------------------------------------
/asset/sql-hint.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | var tables;
15 | var defaultTable;
16 | var keywords;
17 | var identifierQuote;
18 | var CONS = {
19 | QUERY_DIV: ";",
20 | ALIAS_KEYWORD: "AS"
21 | };
22 | var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
23 |
24 | function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
25 |
26 | function getKeywords(editor) {
27 | var mode = editor.doc.modeOption;
28 | if (mode === "sql") mode = "text/x-sql";
29 | return CodeMirror.resolveMode(mode).keywords;
30 | }
31 |
32 | function getIdentifierQuote(editor) {
33 | var mode = editor.doc.modeOption;
34 | if (mode === "sql") mode = "text/x-sql";
35 | return CodeMirror.resolveMode(mode).identifierQuote || "`";
36 | }
37 |
38 | function getText(item) {
39 | return typeof item == "string" ? item : item.text;
40 | }
41 |
42 | function wrapTable(name, value) {
43 | if (isArray(value)) value = {columns: value}
44 | if (!value.text) value.text = name
45 | return value
46 | }
47 |
48 | function parseTables(input) {
49 | var result = {}
50 | if (isArray(input)) {
51 | for (var i = input.length - 1; i >= 0; i--) {
52 | var item = input[i]
53 | result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
54 | }
55 | } else if (input) {
56 | for (var name in input)
57 | result[name.toUpperCase()] = wrapTable(name, input[name])
58 | }
59 | return result
60 | }
61 |
62 | function getTable(name) {
63 | return tables[name.toUpperCase()]
64 | }
65 |
66 | function shallowClone(object) {
67 | var result = {};
68 | for (var key in object) if (object.hasOwnProperty(key))
69 | result[key] = object[key];
70 | return result;
71 | }
72 |
73 | function match(string, word) {
74 | var len = string.length;
75 | var sub = getText(word).substr(0, len);
76 | return string.toUpperCase() === sub.toUpperCase();
77 | }
78 |
79 | function addMatches(result, search, wordlist, formatter) {
80 | if (isArray(wordlist)) {
81 | for (var i = 0; i < wordlist.length; i++)
82 | if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
83 | } else {
84 | for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
85 | var val = wordlist[word]
86 | if (!val || val === true)
87 | val = word
88 | else
89 | val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
90 | if (match(search, val)) result.push(formatter(val))
91 | }
92 | }
93 | }
94 |
95 | function cleanName(name) {
96 | // Get rid name from identifierQuote and preceding dot(.)
97 | if (name.charAt(0) == ".") {
98 | name = name.substr(1);
99 | }
100 | // replace doublicated identifierQuotes with single identifierQuotes
101 | // and remove single identifierQuotes
102 | var nameParts = name.split(identifierQuote+identifierQuote);
103 | for (var i = 0; i < nameParts.length; i++)
104 | nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
105 | return nameParts.join(identifierQuote);
106 | }
107 |
108 | function insertIdentifierQuotes(name) {
109 | var nameParts = getText(name).split(".");
110 | for (var i = 0; i < nameParts.length; i++)
111 | nameParts[i] = identifierQuote +
112 | // doublicate identifierQuotes
113 | nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
114 | identifierQuote;
115 | var escaped = nameParts.join(".");
116 | if (typeof name == "string") return escaped;
117 | name = shallowClone(name);
118 | name.text = escaped;
119 | return name;
120 | }
121 |
122 | function nameCompletion(cur, token, result, editor) {
123 | // Try to complete table, column names and return start position of completion
124 | var useIdentifierQuotes = false;
125 | var nameParts = [];
126 | var start = token.start;
127 | var cont = true;
128 | while (cont) {
129 | cont = (token.string.charAt(0) == ".");
130 | useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
131 |
132 | start = token.start;
133 | nameParts.unshift(cleanName(token.string));
134 |
135 | token = editor.getTokenAt(Pos(cur.line, token.start));
136 | if (token.string == ".") {
137 | cont = true;
138 | token = editor.getTokenAt(Pos(cur.line, token.start));
139 | }
140 | }
141 |
142 | // Try to complete table names
143 | var string = nameParts.join(".");
144 | addMatches(result, string, tables, function(w) {
145 | return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
146 | });
147 |
148 | // Try to complete columns from defaultTable
149 | addMatches(result, string, defaultTable, function(w) {
150 | return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
151 | });
152 |
153 | // Try to complete columns
154 | string = nameParts.pop();
155 | var table = nameParts.join(".");
156 |
157 | var alias = false;
158 | var aliasTable = table;
159 | // Check if table is available. If not, find table by Alias
160 | if (!getTable(table)) {
161 | var oldTable = table;
162 | table = findTableByAlias(table, editor);
163 | if (table !== oldTable) alias = true;
164 | }
165 |
166 | var columns = getTable(table);
167 | if (columns && columns.columns)
168 | columns = columns.columns;
169 |
170 | if (columns) {
171 | addMatches(result, string, columns, function(w) {
172 | var tableInsert = table;
173 | if (alias == true) tableInsert = aliasTable;
174 | if (typeof w == "string") {
175 | w = tableInsert + "." + w;
176 | } else {
177 | w = shallowClone(w);
178 | w.text = tableInsert + "." + w.text;
179 | }
180 | return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
181 | });
182 | }
183 |
184 | return start;
185 | }
186 |
187 | function eachWord(lineText, f) {
188 | var words = lineText.split(/\s+/)
189 | for (var i = 0; i < words.length; i++)
190 | if (words[i]) f(words[i].replace(/[,;]/g, ''))
191 | }
192 |
193 | function findTableByAlias(alias, editor) {
194 | var doc = editor.doc;
195 | var fullQuery = doc.getValue();
196 | var aliasUpperCase = alias.toUpperCase();
197 | var previousWord = "";
198 | var table = "";
199 | var separator = [];
200 | var validRange = {
201 | start: Pos(0, 0),
202 | end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
203 | };
204 |
205 | //add separator
206 | var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
207 | while(indexOfSeparator != -1) {
208 | separator.push(doc.posFromIndex(indexOfSeparator));
209 | indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
210 | }
211 | separator.unshift(Pos(0, 0));
212 | separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
213 |
214 | //find valid range
215 | var prevItem = null;
216 | var current = editor.getCursor()
217 | for (var i = 0; i < separator.length; i++) {
218 | if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
219 | validRange = {start: prevItem, end: separator[i]};
220 | break;
221 | }
222 | prevItem = separator[i];
223 | }
224 |
225 | if (validRange.start) {
226 | var query = doc.getRange(validRange.start, validRange.end, false);
227 |
228 | for (var i = 0; i < query.length; i++) {
229 | var lineText = query[i];
230 | eachWord(lineText, function(word) {
231 | var wordUpperCase = word.toUpperCase();
232 | if (wordUpperCase === aliasUpperCase && getTable(previousWord))
233 | table = previousWord;
234 | if (wordUpperCase !== CONS.ALIAS_KEYWORD)
235 | previousWord = word;
236 | });
237 | if (table) break;
238 | }
239 | }
240 | return table;
241 | }
242 |
243 | CodeMirror.registerHelper("hint", "sql", function(editor, options) {
244 | tables = parseTables(options && options.tables)
245 | var defaultTableName = options && options.defaultTable;
246 | var disableKeywords = options && options.disableKeywords;
247 | defaultTable = defaultTableName && getTable(defaultTableName);
248 | keywords = getKeywords(editor);
249 | identifierQuote = getIdentifierQuote(editor);
250 |
251 | if (defaultTableName && !defaultTable)
252 | defaultTable = findTableByAlias(defaultTableName, editor);
253 |
254 | defaultTable = defaultTable || [];
255 |
256 | if (defaultTable.columns)
257 | defaultTable = defaultTable.columns;
258 |
259 | var cur = editor.getCursor();
260 | var result = [];
261 | var token = editor.getTokenAt(cur), start, end, search;
262 | if (token.end > cur.ch) {
263 | token.end = cur.ch;
264 | token.string = token.string.slice(0, cur.ch - token.start);
265 | }
266 |
267 | if (token.string.match(/^[.`"\w@]\w*$/)) {
268 | search = token.string;
269 | start = token.start;
270 | end = token.end;
271 | } else {
272 | start = end = cur.ch;
273 | search = "";
274 | }
275 | if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
276 | start = nameCompletion(cur, token, result, editor);
277 | } else {
278 | addMatches(result, search, defaultTable, function(w) {return {text:w, className: "CodeMirror-hint-table CodeMirror-hint-default-table"};});
279 | addMatches(
280 | result,
281 | search,
282 | tables,
283 | function(w) {
284 | if (typeof w === 'object') {
285 | w.className = "CodeMirror-hint-table";
286 | } else {
287 | w = {text: w, className: "CodeMirror-hint-table"};
288 | }
289 |
290 | return w;
291 | }
292 | );
293 | if (!disableKeywords)
294 | addMatches(result, search, keywords, function(w) {return {text: w.toUpperCase(), className: "CodeMirror-hint-keyword"};});
295 | }
296 |
297 | return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
298 | });
299 | });
300 |
--------------------------------------------------------------------------------
/asset/sql-qone.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 |
14 | CodeMirror.defineMode("sql", function(config, parserConfig) {
15 | "use strict";
16 |
17 | var client = parserConfig.client || {},
18 | atoms = parserConfig.atoms || {"false": true, "true": true, "null": true},
19 | builtin = parserConfig.builtin || {},
20 | keywords = parserConfig.keywords || {},
21 | operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/,
22 | support = parserConfig.support || {},
23 | hooks = parserConfig.hooks || {},
24 | dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true},
25 | backslashStringEscapes = parserConfig.backslashStringEscapes !== false,
26 | brackets = parserConfig.brackets || /^[\{}\(\)\[\]]/,
27 | punctuation = parserConfig.punctuation || /^[;.,:]/
28 |
29 | function tokenBase(stream, state) {
30 | var ch = stream.next();
31 |
32 | // call hooks from the mime type
33 | if (hooks[ch]) {
34 | var result = hooks[ch](stream, state);
35 | if (result !== false) return result;
36 | }
37 |
38 | if (support.hexNumber &&
39 | ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
40 | || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
41 | // hex
42 | // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
43 | return "number";
44 | } else if (support.binaryNumber &&
45 | (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
46 | || (ch == "0" && stream.match(/^b[01]+/)))) {
47 | // bitstring
48 | // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html
49 | return "number";
50 | } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
51 | // numbers
52 | // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
53 | stream.match(/^[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?/);
54 | support.decimallessFloat && stream.match(/^\.(?!\.)/);
55 | return "number";
56 | } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
57 | // placeholders
58 | return "variable-3";
59 | } else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
60 | // strings
61 | // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
62 | state.tokenize = tokenLiteral(ch);
63 | return state.tokenize(stream, state);
64 | } else if ((((support.nCharCast && (ch == "n" || ch == "N"))
65 | || (support.charsetCast && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
66 | && (stream.peek() == "'" || stream.peek() == '"'))) {
67 | // charset casting: _utf8'str', N'str', n'str'
68 | // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
69 | return "keyword";
70 | } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
71 | // 1-line comment
72 | stream.skipToEnd();
73 | return "comment";
74 | } else if ((support.commentHash && ch == "#")
75 | || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
76 | // 1-line comments
77 | // ref: https://kb.askmonty.org/en/comment-syntax/
78 | stream.skipToEnd();
79 | return "comment";
80 | } else if (ch == "/" && stream.eat("*")) {
81 | // multi-line comments
82 | // ref: https://kb.askmonty.org/en/comment-syntax/
83 | state.tokenize = tokenComment(1);
84 | return state.tokenize(stream, state);
85 | } else if (ch == ".") {
86 | // .1 for 0.1
87 | if (support.zerolessFloat && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i))
88 | return "number";
89 | if (stream.match(/^\.+/))
90 | return null
91 | // .table_name (ODBC)
92 | // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
93 | if (support.ODBCdotTable && stream.match(/^[\w\d_]+/))
94 | return "variable-2";
95 | } else if (operatorChars.test(ch)) {
96 | // operators
97 | stream.eatWhile(operatorChars);
98 | return "operator";
99 | } else if (brackets.test(ch)) {
100 | // brackets
101 | stream.eatWhile(brackets);
102 | return "bracket";
103 | } else if (punctuation.test(ch)) {
104 | // punctuation
105 | stream.eatWhile(punctuation);
106 | return "punctuation";
107 | } else if (ch == '{' &&
108 | (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
109 | // dates (weird ODBC syntax)
110 | // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
111 | return "number";
112 | } else {
113 | stream.eatWhile(/^[_\w\d]/);
114 | var word = stream.current().toLowerCase();
115 | // dates (standard SQL syntax)
116 | // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
117 | if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
118 | return "number";
119 | if (atoms.hasOwnProperty(word)) return "atom";
120 | if (builtin.hasOwnProperty(word)) return "builtin";
121 | if (keywords.hasOwnProperty(word)) return "keyword";
122 | if (client.hasOwnProperty(word)) return "string-2";
123 | return null;
124 | }
125 | }
126 |
127 | // 'string', with char specified in quote escaped by '\'
128 | function tokenLiteral(quote) {
129 | return function(stream, state) {
130 | var escaped = false, ch;
131 | while ((ch = stream.next()) != null) {
132 | if (ch == quote && !escaped) {
133 | state.tokenize = tokenBase;
134 | break;
135 | }
136 | escaped = backslashStringEscapes && !escaped && ch == "\\";
137 | }
138 | return "string";
139 | };
140 | }
141 | function tokenComment(depth) {
142 | return function(stream, state) {
143 | var m = stream.match(/^.*?(\/\*|\*\/)/)
144 | if (!m) stream.skipToEnd()
145 | else if (m[1] == "/*") state.tokenize = tokenComment(depth + 1)
146 | else if (depth > 1) state.tokenize = tokenComment(depth - 1)
147 | else state.tokenize = tokenBase
148 | return "comment"
149 | }
150 | }
151 |
152 | function pushContext(stream, state, type) {
153 | state.context = {
154 | prev: state.context,
155 | indent: stream.indentation(),
156 | col: stream.column(),
157 | type: type
158 | };
159 | }
160 |
161 | function popContext(state) {
162 | state.indent = state.context.indent;
163 | state.context = state.context.prev;
164 | }
165 |
166 | return {
167 | startState: function() {
168 | return {tokenize: tokenBase, context: null};
169 | },
170 |
171 | token: function(stream, state) {
172 | if (stream.sol()) {
173 | if (state.context && state.context.align == null)
174 | state.context.align = false;
175 | }
176 | if (state.tokenize == tokenBase && stream.eatSpace()) return null;
177 |
178 | var style = state.tokenize(stream, state);
179 | if (style == "comment") return style;
180 |
181 | if (state.context && state.context.align == null)
182 | state.context.align = true;
183 |
184 | var tok = stream.current();
185 | if (tok == "(")
186 | pushContext(stream, state, ")");
187 | else if (tok == "[")
188 | pushContext(stream, state, "]");
189 | else if (state.context && state.context.type == tok)
190 | popContext(state);
191 | return style;
192 | },
193 |
194 | indent: function(state, textAfter) {
195 | var cx = state.context;
196 | if (!cx) return CodeMirror.Pass;
197 | var closing = textAfter.charAt(0) == cx.type;
198 | if (cx.align) return cx.col + (closing ? 0 : 1);
199 | else return cx.indent + (closing ? 0 : config.indentUnit);
200 | },
201 |
202 | blockCommentStart: "/*",
203 | blockCommentEnd: "*/",
204 | lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : "--",
205 | closeBrackets: "()[]{}''\"\"``"
206 | };
207 | });
208 |
209 | (function() {
210 | "use strict";
211 |
212 | // `identifier`
213 | function hookIdentifier(stream) {
214 | // MySQL/MariaDB identifiers
215 | // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
216 | var ch;
217 | while ((ch = stream.next()) != null) {
218 | if (ch == "`" && !stream.eat("`")) return "variable-2";
219 | }
220 | stream.backUp(stream.current().length - 1);
221 | return stream.eatWhile(/\w/) ? "variable-2" : null;
222 | }
223 |
224 | // "identifier"
225 | function hookIdentifierDoublequote(stream) {
226 | // Standard SQL /SQLite identifiers
227 | // ref: http://web.archive.org/web/20160813185132/http://savage.net.au/SQL/sql-99.bnf.html#delimited%20identifier
228 | // ref: http://sqlite.org/lang_keywords.html
229 | var ch;
230 | while ((ch = stream.next()) != null) {
231 | if (ch == "\"" && !stream.eat("\"")) return "variable-2";
232 | }
233 | stream.backUp(stream.current().length - 1);
234 | return stream.eatWhile(/\w/) ? "variable-2" : null;
235 | }
236 |
237 | // variable token
238 | function hookVar(stream) {
239 | // variables
240 | // @@prefix.varName @varName
241 | // varName can be quoted with ` or ' or "
242 | // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
243 | if (stream.eat("@")) {
244 | stream.match(/^session\./);
245 | stream.match(/^local\./);
246 | stream.match(/^global\./);
247 | }
248 |
249 | if (stream.eat("'")) {
250 | stream.match(/^.*'/);
251 | return "variable-2";
252 | } else if (stream.eat('"')) {
253 | stream.match(/^.*"/);
254 | return "variable-2";
255 | } else if (stream.eat("`")) {
256 | stream.match(/^.*`/);
257 | return "variable-2";
258 | } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) {
259 | return "variable-2";
260 | }
261 | return null;
262 | };
263 |
264 | // short client keyword token
265 | function hookClient(stream) {
266 | // \N means NULL
267 | // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html
268 | if (stream.eat("N")) {
269 | return "atom";
270 | }
271 | // \g, etc
272 | // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html
273 | return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
274 | }
275 |
276 | // these keywords are used by all SQL dialects (however, a mode can still overwrite it)
277 | var sqlKeywords = "asc desc from in select where limit ";
278 |
279 | // turn a space-separated list into an array
280 | function set(str) {
281 | var obj = {}, words = str.split(" ");
282 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
283 | return obj;
284 | }
285 |
286 |
287 | CodeMirror.defineMIME("text/qone", {
288 | name: "sql",
289 | keywords: set(sqlKeywords + "groupby orderby "),
290 | builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"),
291 | atoms: set("false true null undefined"),
292 | operatorChars: /^[*+\-%<>!=]/,
293 | dateSQL: set("date time timestamp"),
294 | support: set("ODBCdotTable doubleQuote binaryNumber hexNumber")
295 | });
296 | }());
297 |
298 | });
299 |
300 | /*
301 | How Properties of Mime Types are used by SQL Mode
302 | =================================================
303 |
304 | keywords:
305 | A list of keywords you want to be highlighted.
306 | builtin:
307 | A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword").
308 | operatorChars:
309 | All characters that must be handled as operators.
310 | client:
311 | Commands parsed and executed by the client (not the server).
312 | support:
313 | A list of supported syntaxes which are not common, but are supported by more than 1 DBMS.
314 | * ODBCdotTable: .tableName
315 | * zerolessFloat: .1
316 | * doubleQuote
317 | * nCharCast: N'string'
318 | * charsetCast: _utf8'string'
319 | * commentHash: use # char for comments
320 | * commentSlashSlash: use // for comments
321 | * commentSpaceRequired: require a space after -- for comments
322 | atoms:
323 | Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others:
324 | UNKNOWN, INFINITY, UNDERFLOW, NaN...
325 | dateSQL:
326 | Used for date/time SQL standard syntax, because not all DBMS's support same temporal types.
327 | */
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Qone - .NET LINQ in javascript.
6 |
7 |
8 |
87 |
88 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | Qone
110 |
111 |
112 |
113 | .NET LINQ in javascript.
114 |
115 |
116 | var list = [
117 | { name: 'qone', age: 1 },
118 | { name: 'linq', age: 18 },
119 | { name: 'tencent', age: 20 },
120 | { name: 'dntzhang', age: 28 }
121 | ]
122 |
123 | var result = qone({ list }).query(`
124 |
125 |
126 |
133 | `)
134 |
135 | console.log(result)
136 |
137 |
138 |
139 |
140 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "qone",
3 | "version": "2.0.0",
4 | "main": "qone.js",
5 | "description": "Next-generation web query language, extend .NET LINQ for javascript.",
6 | "scripts": {
7 | "lint": "eslint qone.js --fix",
8 | "build": "uglifyjs -o qone.min.js --ie8 --compress --mangle -- qone.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/dntzhang/qone"
13 | },
14 | "keywords": [
15 | "qone",
16 | "linq",
17 | "query"
18 | ],
19 | "dependencies": {},
20 | "devDependencies": {
21 | "eslint": "^4.3.0",
22 | "eslint-config-standard": "^10.2.1",
23 | "eslint-plugin-import": "^2.7.0",
24 | "eslint-plugin-node": "^5.1.1",
25 | "eslint-plugin-promise": "^3.5.0",
26 | "eslint-plugin-standard": "^3.0.1",
27 | "uglifyjs": "^2.4.11"
28 | },
29 | "author": "dntzhang",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/dntzhang/qone/issues/new"
33 | },
34 | "homepage": "https://dntzhang.github.io/qone/"
35 | }
36 |
--------------------------------------------------------------------------------
/qone.min.js:
--------------------------------------------------------------------------------
1 | /* qone v2.0.0 - Next-generation web query language, extend .NET LINQ for javascript.
2 | * By dntzhang https://github.com/dntzhang
3 | * Github: https://github.com/dntzhang/qone
4 | * MIT Licensed.
5 | */
6 | !function(u,t){"object"==typeof module&&module.exports?module.exports=t():u.qone=t()}(this,function(){function u(u,t){return Object.prototype.hasOwnProperty.call(u,t)}function t(u){return"[object Array]"===Object.prototype.toString.call(u)}function e(u){return null!==u&&"object"==typeof u&&!Array.isArray(u)}function i(u){var t,e=[]
7 | for(t in u)e.push(t)
8 | return e}function s(u){var t,e={}
9 | for(t=0;t=48&&57>=u}function r(u){return n(u)||a(u)}function o(u){return u.split("")}function h(u){return x.test(u)?parseInt(u.substr(2),16):_.test(u)?parseInt(u.substr(1),8):g.test(u)?parseFloat(u):void 0}function a(u){return m.letter.test(u)||"_"===u}function A(u){return null===u||void 0===u}function c(u,t,e){var s,n,r,o
11 | if(A(u)||A(t))return!1
12 | if(u.prototype!==t.prototype)return!1
13 | try{r=i(u),o=i(t)}catch(h){return!1}if(r.length!=o.length)return!1
14 | for(r.sort(),o.sort(),s=r.length-1;s>=0;s--)if(r[s]!=o[s])return!1
15 | for(s=r.length-1;s>=0;s--)if(n=r[s],!b(u[n],t[n],e))return!1
16 | return typeof u==typeof t}function p(u){if(null===u||void 0===u)throw new TypeError("Object.assign cannot be called with null or undefined")
17 | return Object(u)}function B(){var u,t,e,i,s
18 | try{if(!Object.assign)return!1
19 | if(u=new String("abc"),u[5]="de","5"===Object.getOwnPropertyNames(u)[0])return!1
20 | for(t={},e=0;10>e;e++)t["_"+String.fromCharCode(e)]=e
21 | return i=Object.getOwnPropertyNames(t).map(function(u){return t[u]}),"0123456789"!==i.join("")?!1:(s={},"abcdefghijklmnopqrst".split("").forEach(function(u){s[u]=u}),"abcdefghijklmnopqrst"!==Object.keys(Object.assign({},s)).join("")?!1:!0)}catch(n){return!1}}var C,l,F,D=s(o(" \r ")),f=s(o("+-*&%=<>!?|~^")),d=s(o("[]{}(),;:")),E=s(o("[{}(,.;:")),y=s(["false","null","true","undefined"]),v={"null":null,undefined:void 0,"true":!0,"false":!1},x=/^0x[0-9a-f]+$/i,_=/^0[0-7]+$/,g=/^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i,k=s(["from","in","where","select","orderby","desc","asc","groupby","limit"]),m={letter:RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),non_spacing_mark:RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),space_combining_mark:RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),connector_punctuation:RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")},b=function(u,t,e){return e||(e={}),u===t?!0:u instanceof Date&&t instanceof Date?u.getTime()===t.getTime():!u||!t||"object"!=typeof u&&"object"!=typeof t?e.strict?u===t:u==t:c(u,t,e)},w=Object.getOwnPropertySymbols,j=Object.prototype.hasOwnProperty,O=Object.prototype.propertyIsEnumerable,M=B()?Object.assign:function(u,t){var e,i,s,n,r,o=p(u)
22 | for(s=1;s"===this.text.charAt(this.pos+1)?(this.col+=2,this.pos+=2,{type:"operator",value:"!="}):"="===t&&"="===this.text.charAt(this.pos+1)?("="===this.text.charAt(this.pos+2)?(this.col+=3,this.pos+=3):(this.col+=2,this.pos+=2),{type:"operator",value:"="}):">"===t&&"="===this.text.charAt(this.pos+1)?(this.col+=2,this.pos+=2,{type:"operator",value:">="}):"<"===t&&"="===this.text.charAt(this.pos+1)?(this.col+=2,this.pos+=2,{type:"operator",value:"<="}):{type:"operator",value:this.next()}:n(t)?this.readNum():"\n"==t?{type:"br",value:this.next()}:'"'==t||"'"==t?this.readString():void 0},start:function(){var u=this.scan()
34 | void 0!==u&&(this.list.push(u),this.start())}},C=function(u){this.tokens=u,this.index=0,this.ast=[]},C.prototype={start:function(){this.parse()},_isKeyword:function(u){return"keyword"===u.type&&("from"===u.value||"where"===u.value||"select"===u.value||"orderby"===u.value||"groupby"===u.value||"limit"===u.value)},_conditions:function(){for(var u,t,e=[],i=this.tokens[this.index];!this._isKeyword(i);)this._is("punc","(")?(this.index++,e.push([this._conditionBlock()])):"&&"===i.value||"||"===i.value?(this.index++,e.push(i.value),e.push(this._condition())):this._is(i,"operator","!")?(u=this.tokens[this.index+1],this._is(u,"punc","(")?(this.index+=2,e.push(["!",this._conditionBlock()])):"name"===u.type&&(this.index++,e.push(["!",this._prop()]))):(t=this._condition(),t.length>0&&e.push(t)),this.index++,i=this.tokens[this.index]
35 | return e},_conditionBlock:function(){for(var u,t=[],e=this.tokens[this.index];!this._is(e,"punc",")")&&!this._isKeyword(e);)this._is(e,"punc","(")?(this.index++,t.push(this._conditionBlock())):"&&"===e.value||"||"===e.value?(this.index++,t.push(e.value),t.push(this._condition())):this._is(e,"operator","!")?(u=this.tokens[this.index+1],this._is(u,"punc","(")?(this.index+=2,t.push(["!",this._conditionBlock()])):"name"===u.type&&(this.index++,t.push(["!",this._prop()]))):t.push(this._condition()),this.index++,e=this.tokens[this.index]
36 | return t},_condition:function(){for(var u,t=[],e=this.tokens[this.index];!this._is(e,"punc",")")&&("&&"!==e.value&&"||"!==e.value||"operator"!==e.type)&&!this._isKeyword(e);)this._is(e,"punc","(")?(this.index++,t.push(this._conditionBlock())):"name"===e.type?t.push(this._prop()):this._is(e,"operator","!")?(u=this.tokens[this.index+1],this._is(u,"punc","(")?(this.index+=2,t.push(["!",this._conditionBlock()])):"name"===u.type&&(this.index++,t.push(["!",this._prop()]))):"atom"===e.type?t.push(v[e.value]):"br"!==e.type&&t.push(e.value),this.index++,e=this.tokens[this.index]
37 | return this.index--,t},_prop:function(){var u=[],t=this.tokens[this.index]
38 | if("name"===t.type&&this.tokens[this.index+1]&&this._is(this.tokens[this.index+1],"punc","("))this.index+=2,u={name:t.value,args:this._args()}
39 | else{for(;t&&("string"===t.type||"number"===t.type||"name"===t.type||"atom"===t.type||"punc"===t.type&&("."===t.value||"["===t.value||"]"===t.value));)("punc"!==t.type||"."!==t.value&&"["!==t.value&&"]"!==t.value)&&(u.length>0||"name"===t.type?u.push(t.value):u=t),this.index++,t=this.tokens[this.index]
40 | this.index--}return u},_parseCondition:function(u){var e=this._splitArray(u,"||"),i=this
41 | return e.forEach(function(u,s){t(u)&&(e[s]=i._parseCondition(u))}),e},_splitArray:function(u,t){if(u.indexOf(t)===-1)return u
42 | var e=[],i=[]
43 | return u.forEach(function(u){u!==t?i.push(u):(e.push(i),e.push(t),i=[])}),e.push(i),e},_select:function(){var u=this.tokens[this.index]
44 | return"{"===u.value?(this.index++,":"===this.tokens[this.index+1].value?this._json():this._simpleJson()):this._propList()},_json:function(){for(var u=[],t=this.tokens[this.index],e={};"}"!==t.value;)":"===this.tokens[this.index+1].value&&(e.key=this._prop()[0]),":"===t.value?(this.index++,e.value=this._prop()):","===t.value&&(this.index++,u.push(e),e={},e.key=this._prop()[0]),this.index++,t=this.tokens[this.index]
45 | return u.push(e),this.index--,{json:u}},_simpleJson:function(){for(var u,t=[],e=this.tokens[this.index];"}"!==e.value;)t=this._propList(),e=this.tokens[this.index]
46 | return this.index--,u=[],t.forEach(function(t){u.push({key:t[t.length-1],value:t})}),{json:u}},_propList:function(){for(var u=[],t=this.tokens[this.index];t&&"}"!==t.value&&!this._isKeyword(t);)","===t.value||"br"===t.type?this.index++:(u.push(this._prop()),this.index++),t=this.tokens[this.index]
47 | return u},_is:function(u,t,e){return u.type===t&&u.value===e},_args:function(){for(var u,t=[],e=this.tokens[this.index];!this._is(e,"punc",")");)this._is(this.tokens[this.index],"punc",",")&&this.index++,u=this._prop(),t.push(u),this.index++,e=this.tokens[this.index]
48 | return t},_orderby:function(){for(var u=[],t=this.tokens[this.index],e={desc:!1};"keyword"!==t.type||"desc"===t.value||"asc"===t.value;)"name"===t.type?e.prop=this._prop():this._is(t,"keyword","desc")?(e.desc=!0,u.push(e),e={desc:!1}):this._is(t,"punc",",")&&(e.prop&&u.push(e),e={desc:!1}),this.index++,t=this.tokens[this.index]
49 | return e.prop&&u.push(e),u},_limit:function(){for(var u=[],t=this.tokens[this.index];t&&!this._isKeyword(t);)"number"===t.type&&u.push(t.value),this.index++,t=this.tokens[this.index]
50 | return u},parse:function(){var u,t=this.tokens[this.index]
51 | if(t)switch(t.type){case"keyword":switch(t.value){case"from":u=this.tokens[this.index+1].value,this.index+=3,this.ast.push(["from",[u,this._prop()]]),this.index+=1,this.parse()
52 | break
53 | case"where":this.index++,this.ast.push(["where",this._parseCondition(this._conditions())]),this.parse()
54 | break
55 | case"select":this.index++,this.ast.push(["select",this._select()]),this.parse()
56 | break
57 | case"orderby":this.index++,this.ast.push(["orderby",this._orderby()]),this.parse()
58 | break
59 | case"groupby":this.index++,this.ast.push(["groupby",this._propList()]),this.parse()
60 | break
61 | case"limit":this.index++,this.ast.push(["limit",this._limit()]),this.parse()}break
62 | case"br":this.index++,this.parse()}}},l=function(u){this.data=this.extend(u),this.ast=null,this.keyMap={}},l.methodMap={},l.prototype={extend:function(u,t){if(null==u||"object"!=typeof u)return u
63 | if(u.constructor!=Object&&u.constructor!=Array)return u
64 | if(u.constructor==Date||u.constructor==RegExp||u.constructor==Function||u.constructor==String||u.constructor==Number||u.constructor==Boolean)return new u.constructor(u)
65 | t=t||new u.constructor
66 | for(var e in u)t[e]=void 0===t[e]?this.extend(u[e],null):t[e]
67 | return t},query:function(u){var t,e=new P(u)
68 | return e.start(),t=new C(e.list),t.start(),this.ast=t.ast,this.exce(),this.result},preprocessData:function(u,t){t.forEach(function(t,e,i){i[e]={},i[e][u]=t})},productSelf:function(u,t){var e=this,i=[]
69 | this.cp.forEach(function(s){var n=JSON.parse(JSON.stringify(e._getDataByPath(s,t)))
70 | e.preprocessData(u,n),e.productOut([s],n,i)}),this.cp=i},exce:function(){for(var u,t,e,s,n,r,o=this.ast,h=0,a=o.length;a>h;h++)switch(t=o[h],t[0]){case"from":e=t[1][1][0],this.keyMap[e]?(this.keyMap[t[1][0]]=t[1][1],this.productSelf(t[1][0],t[1][1],this.keyMap,this.cp)):(u=t[1][0],s=this._getDataByPath(this.data,t[1][1]),this.preprocessData(u,s),this.cp?this.cp=this.product(this.cp,s):this.cp=s,this.keyMap[t[1][0]]=t[1][1]),"where"===o[h+1][0]&&(this.filter(o[h+1][1]),h++)
71 | break
72 | case"where":this.filter(o[h][1])
73 | break
74 | case"select":this.select(t[1])
75 | break
76 | case"orderby":n=[],r=[],t[1].forEach(function(u){n.push(u.prop),r.push(u.desc?"desc":"asc")}),this._orderby(this.cp,n,r)
77 | break
78 | case"groupby":this.groupby(this.cp,t[1]),u=i(this.keyMap)[0],this.result.forEach(function(t){t.forEach(function(t,e,i){i[e]=t[u]})})
79 | break
80 | case"limit":this.limitData(t[1])}},limitData:function(u){this.result=this.result.splice(u[0],u[1])},groupby:function(u,i,s){var n,r,o,h,a,A,c,p,B=this
81 | for("function"==typeof i?n=i:(e(i)&&(s=i,i=[]),s=s||{},void 0===s.strict&&(s.strict=!0),i=[].concat(i).filter(Boolean),r=i.length,n=0===r?function(u,t){return b(u,t,s)}:function(u,e){for(var n,o,h,a=-1;++ae;e++)if("object"==typeof u[e]){t=!1
90 | break}return t},_check:function(u,e){var i,s,n,r=this,o=e.length
91 | if(1===o&&t(e))return this._check(u,e[0])
92 | if(2===o&&"!"===e[0])return!this._check(u,e[1])
93 | if(this._isBool(e))return t(e)?this._getDataByPath(u,e):this.callMethod(u,e.name,e.args)
94 | if(3===o&&"||"!==e[1]&&"&&"!==e[1])return this._checkCond(u,e)
95 | for(i=0,s=!0;o>i;){if(n=e[i],s=r._check(u,n),i++,s){if("||"===e[i])return!0}else if("&&"===e[i])return!1
96 | i++}return s},_checkCond:function(u,i){var s=!0,n=i[0],r=i[2]
97 | return t(n)?n=this._getDataByPath(u,n):e(n)&&(n=this.callMethod(u,n.name,n.args)),t(r)?r=this._getDataByPath(u,r):e(r)&&(r=this.callMethod(u,r.name,r.args)),this._cond(n,i[1],r)||(s=!1),s},_cond:function(u,t,e){switch(t){case">":return u>e
98 | case"<":return e>u
99 | case">=":return u>=e
100 | case"<=":return e>=u
101 | case"=":return u===e
102 | case"!=":return u!==e}},_getDataByPath:function(u,t){var e=u
103 | return t.forEach(function(u,t){e=e[u]}),e},_orderby:function(u,e,i){var s,n,r,o="asc",h=this
104 | return"length"in u&&"object"==typeof u?(i instanceof Array||(s=i||o),e=e instanceof Array?e:[e],u.sort(function(u,a){var A,c,p,B=e.length
105 | if(u&&a)for(A=0;B>A;A++){if(p=e[A],c="asc"==(s||i[A]||o)?-1:1,t(p)?(n=h._getDataByPath(u,p),r=h._getDataByPath(a,p)):(n=h.callMethod(u,p.name,p.args),r=h.callMethod(a,p.name,p.args)),n>r)return-c
106 | if(r>n)return c}return 0})):[]}},F=function(u){if(2!==arguments.length)return new l(u)
107 | var t=arguments[0]
108 | l.methodMap[t]&&console.warn("["+t+"] method has been defined. you will rewrite it."),l.methodMap[t]=arguments[1]}})
109 |
110 |
--------------------------------------------------------------------------------
/test/clone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | aa
10 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Qone Unit Testing
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/test/index.ie.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Qone Unit Testing
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/test/lib/qunit.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * QUnit 2.6.1-pre
3 | * https://qunitjs.com/
4 | *
5 | * Copyright jQuery Foundation and other contributors
6 | * Released under the MIT license
7 | * https://jquery.org/license
8 | *
9 | * Date: 2018-03-27T02:25Z
10 | */
11 |
12 | /** Font Family and Sizes */
13 |
14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult {
15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
16 | }
17 |
18 | #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
19 | #qunit-tests { font-size: smaller; }
20 |
21 |
22 | /** Resets */
23 |
24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 |
30 | /** Header (excluding toolbar) */
31 |
32 | #qunit-header {
33 | padding: 0.5em 0 0.5em 1em;
34 |
35 | color: #8699A4;
36 | background-color: #0D3349;
37 |
38 | font-size: 1.5em;
39 | line-height: 1em;
40 | font-weight: 400;
41 |
42 | border-radius: 5px 5px 0 0;
43 | }
44 |
45 | #qunit-header a {
46 | text-decoration: none;
47 | color: #C2CCD1;
48 | }
49 |
50 | #qunit-header a:hover,
51 | #qunit-header a:focus {
52 | color: #FFF;
53 | }
54 |
55 | #qunit-banner {
56 | height: 5px;
57 | }
58 |
59 | #qunit-filteredTest {
60 | padding: 0.5em 1em 0.5em 1em;
61 | color: #366097;
62 | background-color: #F4FF77;
63 | }
64 |
65 | #qunit-userAgent {
66 | padding: 0.5em 1em 0.5em 1em;
67 | color: #FFF;
68 | background-color: #2B81AF;
69 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
70 | }
71 |
72 |
73 | /** Toolbar */
74 |
75 | #qunit-testrunner-toolbar {
76 | padding: 0.5em 1em 0.5em 1em;
77 | color: #5E740B;
78 | background-color: #EEE;
79 | }
80 |
81 | #qunit-testrunner-toolbar .clearfix {
82 | height: 0;
83 | clear: both;
84 | }
85 |
86 | #qunit-testrunner-toolbar label {
87 | display: inline-block;
88 | }
89 |
90 | #qunit-testrunner-toolbar input[type=checkbox],
91 | #qunit-testrunner-toolbar input[type=radio] {
92 | margin: 3px;
93 | vertical-align: -2px;
94 | }
95 |
96 | #qunit-testrunner-toolbar input[type=text] {
97 | box-sizing: border-box;
98 | height: 1.6em;
99 | }
100 |
101 | .qunit-url-config,
102 | .qunit-filter,
103 | #qunit-modulefilter {
104 | display: inline-block;
105 | line-height: 2.1em;
106 | }
107 |
108 | .qunit-filter,
109 | #qunit-modulefilter {
110 | float: right;
111 | position: relative;
112 | margin-left: 1em;
113 | }
114 |
115 | .qunit-url-config label {
116 | margin-right: 0.5em;
117 | }
118 |
119 | #qunit-modulefilter-search {
120 | box-sizing: border-box;
121 | width: 400px;
122 | }
123 |
124 | #qunit-modulefilter-search-container:after {
125 | position: absolute;
126 | right: 0.3em;
127 | content: "\25bc";
128 | color: black;
129 | }
130 |
131 | #qunit-modulefilter-dropdown {
132 | /* align with #qunit-modulefilter-search */
133 | box-sizing: border-box;
134 | width: 400px;
135 | position: absolute;
136 | right: 0;
137 | top: 50%;
138 | margin-top: 0.8em;
139 |
140 | border: 1px solid #D3D3D3;
141 | border-top: none;
142 | border-radius: 0 0 .25em .25em;
143 | color: #000;
144 | background-color: #F5F5F5;
145 | z-index: 99;
146 | }
147 |
148 | #qunit-modulefilter-dropdown a {
149 | color: inherit;
150 | text-decoration: none;
151 | }
152 |
153 | #qunit-modulefilter-dropdown .clickable.checked {
154 | font-weight: bold;
155 | color: #000;
156 | background-color: #D2E0E6;
157 | }
158 |
159 | #qunit-modulefilter-dropdown .clickable:hover {
160 | color: #FFF;
161 | background-color: #0D3349;
162 | }
163 |
164 | #qunit-modulefilter-actions {
165 | display: block;
166 | overflow: auto;
167 |
168 | /* align with #qunit-modulefilter-dropdown-list */
169 | font: smaller/1.5em sans-serif;
170 | }
171 |
172 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > * {
173 | box-sizing: border-box;
174 | max-height: 2.8em;
175 | display: block;
176 | padding: 0.4em;
177 | }
178 |
179 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > button {
180 | float: right;
181 | font: inherit;
182 | }
183 |
184 | #qunit-modulefilter-dropdown #qunit-modulefilter-actions > :last-child {
185 | /* insert padding to align with checkbox margins */
186 | padding-left: 3px;
187 | }
188 |
189 | #qunit-modulefilter-dropdown-list {
190 | max-height: 200px;
191 | overflow-y: auto;
192 | margin: 0;
193 | border-top: 2px groove threedhighlight;
194 | padding: 0.4em 0 0;
195 | font: smaller/1.5em sans-serif;
196 | }
197 |
198 | #qunit-modulefilter-dropdown-list li {
199 | white-space: nowrap;
200 | overflow: hidden;
201 | text-overflow: ellipsis;
202 | }
203 |
204 | #qunit-modulefilter-dropdown-list .clickable {
205 | display: block;
206 | padding-left: 0.15em;
207 | }
208 |
209 |
210 | /** Tests: Pass/Fail */
211 |
212 | #qunit-tests {
213 | list-style-position: inside;
214 | }
215 |
216 | #qunit-tests li {
217 | padding: 0.4em 1em 0.4em 1em;
218 | border-bottom: 1px solid #FFF;
219 | list-style-position: inside;
220 | }
221 |
222 | #qunit-tests > li {
223 | display: none;
224 | }
225 |
226 | #qunit-tests li.running,
227 | #qunit-tests li.pass,
228 | #qunit-tests li.fail,
229 | #qunit-tests li.skipped,
230 | #qunit-tests li.aborted {
231 | display: list-item;
232 | }
233 |
234 | #qunit-tests.hidepass {
235 | position: relative;
236 | }
237 |
238 | #qunit-tests.hidepass li.running,
239 | #qunit-tests.hidepass li.pass:not(.todo) {
240 | visibility: hidden;
241 | position: absolute;
242 | width: 0;
243 | height: 0;
244 | padding: 0;
245 | border: 0;
246 | margin: 0;
247 | }
248 |
249 | #qunit-tests li strong {
250 | cursor: pointer;
251 | }
252 |
253 | #qunit-tests li.skipped strong {
254 | cursor: default;
255 | }
256 |
257 | #qunit-tests li a {
258 | padding: 0.5em;
259 | color: #C2CCD1;
260 | text-decoration: none;
261 | }
262 |
263 | #qunit-tests li p a {
264 | padding: 0.25em;
265 | color: #6B6464;
266 | }
267 | #qunit-tests li a:hover,
268 | #qunit-tests li a:focus {
269 | color: #000;
270 | }
271 |
272 | #qunit-tests li .runtime {
273 | float: right;
274 | font-size: smaller;
275 | }
276 |
277 | .qunit-assert-list {
278 | margin-top: 0.5em;
279 | padding: 0.5em;
280 |
281 | background-color: #FFF;
282 |
283 | border-radius: 5px;
284 | }
285 |
286 | .qunit-source {
287 | margin: 0.6em 0 0.3em;
288 | }
289 |
290 | .qunit-collapsed {
291 | display: none;
292 | }
293 |
294 | #qunit-tests table {
295 | border-collapse: collapse;
296 | margin-top: 0.2em;
297 | }
298 |
299 | #qunit-tests th {
300 | text-align: right;
301 | vertical-align: top;
302 | padding: 0 0.5em 0 0;
303 | }
304 |
305 | #qunit-tests td {
306 | vertical-align: top;
307 | }
308 |
309 | #qunit-tests pre {
310 | margin: 0;
311 | white-space: pre-wrap;
312 | word-wrap: break-word;
313 | }
314 |
315 | #qunit-tests del {
316 | color: #374E0C;
317 | background-color: #E0F2BE;
318 | text-decoration: none;
319 | }
320 |
321 | #qunit-tests ins {
322 | color: #500;
323 | background-color: #FFCACA;
324 | text-decoration: none;
325 | }
326 |
327 | /*** Test Counts */
328 |
329 | #qunit-tests b.counts { color: #000; }
330 | #qunit-tests b.passed { color: #5E740B; }
331 | #qunit-tests b.failed { color: #710909; }
332 |
333 | #qunit-tests li li {
334 | padding: 5px;
335 | background-color: #FFF;
336 | border-bottom: none;
337 | list-style-position: inside;
338 | }
339 |
340 | /*** Passing Styles */
341 |
342 | #qunit-tests li li.pass {
343 | color: #3C510C;
344 | background-color: #FFF;
345 | border-left: 10px solid #C6E746;
346 | }
347 |
348 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
349 | #qunit-tests .pass .test-name { color: #366097; }
350 |
351 | #qunit-tests .pass .test-actual,
352 | #qunit-tests .pass .test-expected { color: #999; }
353 |
354 | #qunit-banner.qunit-pass { background-color: #C6E746; }
355 |
356 | /*** Failing Styles */
357 |
358 | #qunit-tests li li.fail {
359 | color: #710909;
360 | background-color: #FFF;
361 | border-left: 10px solid #EE5757;
362 | white-space: pre;
363 | }
364 |
365 | #qunit-tests > li:last-child {
366 | border-radius: 0 0 5px 5px;
367 | }
368 |
369 | #qunit-tests .fail { color: #000; background-color: #EE5757; }
370 | #qunit-tests .fail .test-name,
371 | #qunit-tests .fail .module-name { color: #000; }
372 |
373 | #qunit-tests .fail .test-actual { color: #EE5757; }
374 | #qunit-tests .fail .test-expected { color: #008000; }
375 |
376 | #qunit-banner.qunit-fail { background-color: #EE5757; }
377 |
378 |
379 | /*** Aborted tests */
380 | #qunit-tests .aborted { color: #000; background-color: orange; }
381 | /*** Skipped tests */
382 |
383 | #qunit-tests .skipped {
384 | background-color: #EBECE9;
385 | }
386 |
387 | #qunit-tests .qunit-todo-label,
388 | #qunit-tests .qunit-skipped-label {
389 | background-color: #F4FF77;
390 | display: inline-block;
391 | font-style: normal;
392 | color: #366097;
393 | line-height: 1.8em;
394 | padding: 0 0.5em;
395 | margin: -0.4em 0.4em -0.4em 0;
396 | }
397 |
398 | #qunit-tests .qunit-todo-label {
399 | background-color: #EEE;
400 | }
401 |
402 | /** Result */
403 |
404 | #qunit-testresult {
405 | color: #2B81AF;
406 | background-color: #D2E0E6;
407 |
408 | border-bottom: 1px solid #FFF;
409 | }
410 | #qunit-testresult .clearfix {
411 | height: 0;
412 | clear: both;
413 | }
414 | #qunit-testresult .module-name {
415 | font-weight: 700;
416 | }
417 | #qunit-testresult-display {
418 | padding: 0.5em 1em 0.5em 1em;
419 | width: 85%;
420 | float:left;
421 | }
422 | #qunit-testresult-controls {
423 | padding: 0.5em 1em 0.5em 1em;
424 | width: 10%;
425 | float:left;
426 | }
427 |
428 | /** Fixture */
429 |
430 | #qunit-fixture {
431 | position: absolute;
432 | top: -10000px;
433 | left: -10000px;
434 | width: 1000px;
435 | height: 1000px;
436 | }
437 |
--------------------------------------------------------------------------------
/test/test.ie.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | QUnit.test("Basic test", function (assert) {
4 | var arr = [1, 2, 3, 4, 5];
5 |
6 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select n\n ");
7 |
8 | assert.deepEqual(result, [4, 5]);
9 | });
10 |
11 | QUnit.test("Query json array", function (assert) {
12 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
13 |
14 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 18\n select n\n ");
15 |
16 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }]);
17 | });
18 |
19 | QUnit.test("Multi conditional query", function (assert) {
20 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
21 |
22 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 10 && n.name = 'linq'\n select n\n ");
23 |
24 | assert.deepEqual(result, [{ "name": "linq", "age": 18 }]);
25 | });
26 |
27 | QUnit.test("Select test", function (assert) {
28 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
29 |
30 | var result = qone({ list: list }).query("\n from n in list \n where n.age < 20\n select n.age, n.name\n ");
31 |
32 | assert.deepEqual(result, [[1, "qone"], [18, "linq"]]);
33 | });
34 |
35 | QUnit.test("Select JSON test", function (assert) {
36 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
37 |
38 | var result = qone({ list: list }).query("\n from n in list \n where n.age < 20\n select {n.age, n.name}\n ");
39 |
40 | assert.deepEqual(result, [{ "age": 1, "name": "qone" }, { "age": 18, "name": "linq" }]);
41 | });
42 |
43 | QUnit.test("Select full JSON test", function (assert) {
44 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
45 |
46 | var result = qone({ list: list }).query("\n from n in list \n where n.age < 20\n select {a : n.age, b : n.name}\n ");
47 |
48 | assert.deepEqual(result, [{ "a": 1, "b": "qone" }, { "a": 18, "b": "linq" }]);
49 | });
50 |
51 | QUnit.test("|| conditional test", function (assert) {
52 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
53 |
54 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 19 || n.age < 2\n select n\n ");
55 |
56 | assert.deepEqual(result, [{ "name": "qone", "age": 1 }, { "name": "dntzhang", "age": 28 }]);
57 | });
58 |
59 | QUnit.test("|| and && conditional test", function (assert) {
60 | var list = [{ name: 'qone', age: 0 }, { name: 'linq', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
61 |
62 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 17 || n.age < 2 && n.name != 'dntzhang'\n select n\n ");
63 |
64 | assert.deepEqual(result, [{ "name": "qone", "age": 0 }, { "name": "linq", "age": 1 }, { "name": "linq", "age": 18 }, { "name": "dntzhang", "age": 28 }]);
65 | });
66 |
67 | QUnit.test("(), || and && conditional test", function (assert) {
68 | var list = [{ name: 'qone', age: 0 }, { name: 'linq', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
69 |
70 | var result = qone({ list: list }).query("\n from n in list \n where (n.age > 17 || n.age < 2) && n.name != 'dntzhang'\n select n\n ");
71 |
72 | assert.deepEqual(result, [{ "name": "qone", "age": 0 }, { "name": "linq", "age": 1 }, { "name": "linq", "age": 18 }]);
73 | });
74 |
75 | QUnit.test("Query from prop", function (assert) {
76 | var data = {
77 | users: [{ name: 'qone', age: 1 }, { name: 'dntzhang', age: 17 }, { name: 'dntzhang2', age: 27 }]
78 | };
79 |
80 | var result = qone({ data: data }).query("\n from n in data.users \n where n.age < 10\n select n\n ");
81 |
82 | assert.deepEqual(result, [{ "name": "qone", "age": 1 }]);
83 | });
84 |
85 | QUnit.test("Multi datasource ", function (assert) {
86 |
87 | var listA = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
88 |
89 | var listB = [{ name: 'x', age: 11 }, { name: 'xx', age: 12 }, { name: 'xxx', age: 13 }];
90 |
91 | var result = qone({ listA: listA, listB: listB }).query("\n from a in listA \n from b in listB \n where a.age < 20 && b.age > 11\n select a, b\n ");
92 |
93 | assert.deepEqual(result, [[{ "name": "qone", "age": 1 }, { "name": "xx", "age": 12 }], [{ "name": "qone", "age": 1 }, { "name": "xxx", "age": 13 }], [{ "name": "linq", "age": 18 }, { "name": "xx", "age": 12 }], [{ "name": "linq", "age": 18 }, { "name": "xxx", "age": 13 }]]);
94 | });
95 |
96 | QUnit.test("Multi datasource with props condition", function (assert) {
97 |
98 | var listA = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
99 |
100 | var listB = [{ name: 'x', age: 11 }, { name: 'xx', age: 18 }, { name: 'xxx', age: 13 }];
101 |
102 | var result = qone({ listA: listA, listB: listB }).query("\n from a in listA \n from b in listB \n where a.age = b.age\n select a, b\n ");
103 |
104 | assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]]);
105 | });
106 |
107 | QUnit.test("Bool condition ", function (assert) {
108 |
109 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
110 |
111 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby\n select a\n ");
112 |
113 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }]);
114 | });
115 |
116 | QUnit.test("Bool condition ", function (assert) {
117 |
118 | var list = [{ name: 'qone', age: 1, isBaby: [true] }, { name: 'linq', age: 18, isBaby: [false] }, { name: 'dntzhang', age: 28, isBaby: [false] }];
119 |
120 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby[0]\n select a\n ");
121 |
122 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: [true] }]);
123 | });
124 |
125 | QUnit.test("Multi from test ", function (assert) {
126 |
127 | var list = [{ name: 'qone', age: 1, isBaby: true, colors: ['red', 'green', 'blue'] }, { name: 'linq', age: 18, colors: ['red', 'blue'] }, { name: 'dntzhang', age: 28, colors: ['red', 'blue'] }];
128 |
129 | var result = qone({ list: list }).query("\n from a in list \n from c in a.colors \n where c = 'green'\n select a, c\n ");
130 |
131 | assert.deepEqual(result, [[{ "name": "qone", "age": 1, "isBaby": true, "colors": ["red", "green", "blue"] }, "green"]]);
132 | });
133 |
134 | QUnit.test("Multi deep from test ", function (assert) {
135 |
136 | 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] }] }];
137 |
138 | var result = qone({ list: list }).query("\n from a in list \n from c in a.colors \n from d in c.xx \n select a, c,d\n ");
139 |
140 | assert.equal(result.length, 18);
141 | });
142 |
143 | QUnit.test("Multi deep from test ", function (assert) {
144 |
145 | 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] }] }];
146 |
147 | var result = qone({ list: list }).query("\n from a in list \n from c in a.colors \n from d in c.xx \n where d === 100\n select a.name, c,d\n ");
148 |
149 | assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]]);
150 | });
151 |
152 | QUnit.test("Deep prop path test ", function (assert) {
153 |
154 | var list = [{ name: 'qone', age: 1, fullName: { first: 'q', last: 'one' } }, { name: 'linq', age: 18, fullName: { first: 'l', last: 'inq' } }, { name: 'dntzhang', age: 28, fullName: { first: 'dnt', last: 'zhang' } }];
155 |
156 | var result = qone({ list: list }).query("\n from a in list \n where a.fullName.first === 'dnt'\n select a.name\n ");
157 |
158 | assert.deepEqual(result, ["dntzhang"]);
159 | });
160 |
161 | QUnit.test("Method test 1", function (assert) {
162 | var arr = [1, 2, 3, 4, 5];
163 |
164 | qone('square', function (num) {
165 | return num * num;
166 | });
167 |
168 | var result = qone({ arr: arr }).query("\n from n in arr \n where square(n) > 10\n select n\n ");
169 |
170 | assert.deepEqual(result, [4, 5]);
171 | });
172 |
173 | QUnit.test("Method test 2", function (assert) {
174 | var arr = [1, 2, 3, 4, 5];
175 |
176 | qone('square', function (num) {
177 | return num * num;
178 | });
179 |
180 | var result = qone({ arr: arr }).query("\n from n in arr \n where 10 > square(n)\n select n\n ");
181 |
182 | assert.deepEqual(result, [1, 2, 3]);
183 | });
184 |
185 | QUnit.test("Method test 3", function (assert) {
186 | var arr = [1, 2, 3, 4, 5];
187 |
188 | qone('square', function (num) {
189 | return num * num;
190 | });
191 |
192 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select square(n)\n ");
193 |
194 | assert.deepEqual(result, [16, 25]);
195 | });
196 |
197 | QUnit.test("Method test 4", function (assert) {
198 | var arr = [1, 2, 3, 4, 5];
199 |
200 | qone('square', function (num) {
201 | return num * num;
202 | });
203 |
204 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select n, square(n)\n ");
205 |
206 | assert.deepEqual(result, [[4, 16], [5, 25]]);
207 | });
208 |
209 | QUnit.test("Method test 5", function (assert) {
210 | var arr = [1, 2, 3, 4, 5];
211 |
212 | qone('square', function (num) {
213 | return num * num;
214 | });
215 |
216 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select { value : n, squareValue : square(n) }\n ");
217 |
218 | assert.deepEqual(result, [{ "value": 4, "squareValue": 16 }, { "value": 5, "squareValue": 25 }]);
219 | });
220 |
221 | QUnit.test("Method test 6", function (assert) {
222 | var arr = [1, 2, 3, 4, 5];
223 |
224 | qone('square', function (num) {
225 | return num * num;
226 | });
227 |
228 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select { squareValue : square(n) }\n ");
229 |
230 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }]);
231 | });
232 |
233 | QUnit.test("Method test 7", function (assert) {
234 | var arr = [1, 2, 3, 4, 5];
235 |
236 | qone('square', function (num) {
237 | return num * num;
238 | });
239 |
240 | var result = qone({ arr: arr }).query("\n from n in arr \n where n > 3\n select { squareValue : square(n) }\n ");
241 |
242 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }]);
243 | });
244 |
245 | QUnit.test("Method test 8", function (assert) {
246 | var arr = [1, 2, 3, 4, 5];
247 |
248 | qone('square', function (num) {
249 | return num * num;
250 | });
251 |
252 | qone('sqrt', function (num) {
253 | return Math.sqrt(num);
254 | });
255 |
256 | var result = qone({ arr: arr }).query("\n from n in arr \n where sqrt(n) >= 2 \n select { squareValue : square(n) }\n ");
257 |
258 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }]);
259 | });
260 |
261 | QUnit.test("Method test 9", function (assert) {
262 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 19 }, { name: 'dntzhang', age: 28 }];
263 |
264 | qone('greaterThan18', function (num) {
265 | return num > 18;
266 | });
267 |
268 | var result = qone({ list: list }).query("\n from n in list \n where greaterThan18(n.age) && n.name = 'dntzhang'\n select n\n ");
269 |
270 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }]);
271 | });
272 |
273 | QUnit.test("Method test 10", function (assert) {
274 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 19 }, { name: 'dntzhang', age: 28 }];
275 |
276 | qone('greaterThan18', function (num) {
277 | return num > 18;
278 | });
279 |
280 | var result = qone({ list: list }).query("\n from n in list \n where greaterThan18(n.age) && n.name = 'dntzhang'\n select n\n ");
281 |
282 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }]);
283 | });
284 |
285 | QUnit.test("Order by test 1", function (assert) {
286 | var list = [{ name: 'linq2', age: 7 }, { name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
287 |
288 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n orderby n.age desc\n select n\n ");
289 |
290 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }, { "name": "linq", "age": 18 }, { "name": "linq2", "age": 7 }, { "name": "qone", "age": 1 }]);
291 | });
292 |
293 | QUnit.test("Order by test 2", function (assert) {
294 | var list = [{ name: 'linq2', age: 7 }, { name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'ainq', age: 18 }, { name: 'dntzhang', age: 28 }];
295 |
296 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n orderby n.age asc, n.name desc\n select n\n ");
297 |
298 | assert.deepEqual(result, [{ "name": "qone", "age": 1 }, { "name": "linq2", "age": 7 }, { "name": "linq", "age": 18 }, { "name": "ainq", "age": 18 }, { "name": "dntzhang", "age": 28 }]);
299 | });
300 |
301 | QUnit.test("Order by test 3", function (assert) {
302 | var list = [{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 2 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang3', age: 29, age2: 1 }];
303 |
304 | qone('sum', function (a, b) {
305 | return a + b;
306 | });
307 |
308 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n orderby sum(n.age,n.age2) \n select n\n ");
309 |
310 | assert.deepEqual(result, [{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 2 }, { name: 'dntzhang3', age: 29, age2: 1 }]);
311 | });
312 |
313 | QUnit.test("Order by test 4", function (assert) {
314 | var list = [{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 2 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang3', age: 29, age2: 1 }];
315 |
316 | qone('sum', function (a, b) {
317 | return a + b;
318 | });
319 |
320 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n orderby sum(n.age,n.age2) ,n.name\n select n\n ");
321 |
322 | assert.deepEqual(result, [{ name: 'linq', age: 18, age2: 1 }, { name: 'qone', age: 17, age2: 2 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 2 }, { name: 'dntzhang3', age: 29, age2: 1 }]);
323 | });
324 |
325 | QUnit.test("Simple groupby test 1", function (assert) {
326 | var list = [{ name: 'qone', age: 1 }, { name: 'linq', age: 18 }, { name: 'dntzhang1', age: 28 }, { name: 'dntzhang2', age: 28 }, { name: 'dntzhang3', age: 29 }];
327 |
328 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 18\n groupby n.age\n ");
329 |
330 | assert.deepEqual(result, [[{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }], [{ "name": "dntzhang3", "age": 29 }]]);
331 | });
332 |
333 | QUnit.test("Simple groupby test 2", function (assert) {
334 | var list = [{ name: 'qone', age: 1 }, { name: 'qone', age: 1 }, { name: 'dntzhang', age: 28 }, { name: 'dntzhang2', age: 28 }, { name: 'dntzhang', age: 29 }];
335 |
336 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n groupby n.age,n.name\n ");
337 |
338 | assert.deepEqual(result, [[{ "name": "qone", "age": 1 }, { "name": "qone", "age": 1 }], [{ "name": "dntzhang", "age": 28 }], [{ "name": "dntzhang2", "age": 28 }], [{ "name": "dntzhang", "age": 29 }]]);
339 | });
340 |
341 | QUnit.test("Simple groupby with method", function (assert) {
342 | var list = [{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 1 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang3', age: 29, age2: 1 }];
343 | qone('sum', function (a, b) {
344 | return a + b;
345 | });
346 |
347 | var result = qone({ list: list }).query("\n from n in list \n groupby sum(n.age,n.age2)\n ");
348 |
349 | assert.deepEqual(result, [[{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }], [{ name: 'dntzhang1', age: 28, age2: 1 }, { name: 'dntzhang2', age: 28, age2: 1 }], [{ name: 'dntzhang3', age: 29, age2: 1 }]]);
350 | });
351 |
352 | QUnit.test("Simple groupby with method", function (assert) {
353 | var list = [{ name: 'qone', age: 17, age2: 2 }, { name: 'qone', age: 18, age2: 1 }, { name: 'dntzhang1', age: 28, age2: 1 }, { name: 'dntzhang2', age: 28, age2: 1 }, { name: 'dntzhang3', age: 29, age2: 1 }];
354 | qone('sum', function (a, b) {
355 | return a + b;
356 | });
357 |
358 | var result = qone({ list: list }).query("\n from n in list \n groupby sum(n.age,n.age2), n.name\n ");
359 |
360 | assert.deepEqual(result, [[{ name: 'qone', age: 17, age2: 2 }, { name: 'qone', age: 18, age2: 1 }], [{ name: 'dntzhang1', age: 28, age2: 1 }], [{ name: 'dntzhang2', age: 28, age2: 1 }], [{ name: 'dntzhang3', age: 29, age2: 1 }]]);
361 | });
362 |
363 | QUnit.test("Bool condition 1 ", function (assert) {
364 |
365 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
366 |
367 | var result = qone({ list: list }).query("\n from a in list \n where !a.isBaby\n select a\n ");
368 |
369 | assert.deepEqual(result, [{ "name": "linq", "age": 18 }, { "name": "dntzhang", "age": 28 }]);
370 | });
371 |
372 | QUnit.test("Bool condition 2 ", function (assert) {
373 |
374 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
375 |
376 | var result = qone({ list: list }).query("\n from a in list \n where !a.isBaby && a.name='qone'\n select a\n ");
377 |
378 | assert.deepEqual(result, []);
379 | });
380 |
381 | QUnit.test("Bool condition 3 ", function (assert) {
382 |
383 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
384 |
385 | var result = qone({ list: list }).query("\n from a in list \n where !(a.isBaby && a.name='qone') \n select a\n ");
386 |
387 | assert.deepEqual(result, [{ name: 'linq', age: 18 }, { "name": "dntzhang", "age": 28 }]);
388 | });
389 |
390 | QUnit.test("Bool condition 4 ", function (assert) {
391 |
392 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
393 |
394 | var result = qone({ list: list }).query("\n from a in list \n where !(a.isBaby && a.name='qone') && a.age = 28\n select a\n ");
395 |
396 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }]);
397 | });
398 |
399 | QUnit.test("Bool condition 5 ", function (assert) {
400 |
401 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
402 |
403 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = true\n select a\n ");
404 |
405 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }]);
406 | });
407 |
408 | QUnit.test("Bool condition 6 ", function (assert) {
409 |
410 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
411 |
412 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = true\n select a\n ");
413 |
414 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }]);
415 | });
416 |
417 | QUnit.test("Bool condition 7 ", function (assert) {
418 |
419 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
420 |
421 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = true\n select a\n ");
422 |
423 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }]);
424 | });
425 |
426 | QUnit.test("Bool condition 8 ", function (assert) {
427 |
428 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
429 |
430 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = undefined\n select a\n ");
431 |
432 | assert.deepEqual(result, [{ name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }]);
433 | });
434 |
435 | QUnit.test("Bool condition 9 ", function (assert) {
436 |
437 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: false }];
438 |
439 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = false\n select a\n ");
440 |
441 | assert.deepEqual(result, [{ name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: false }]);
442 | });
443 |
444 | QUnit.test("Bool condition 10 ", function (assert) {
445 |
446 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: null }];
447 |
448 | var result = qone({ list: list }).query("\n from a in list \n where a.isBaby = false || a.isBaby = null\n select a\n ");
449 |
450 | assert.deepEqual(result, [{ name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: null }]);
451 | });
452 |
453 | QUnit.test("Bool condition 11 ", function (assert) {
454 |
455 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
456 |
457 | var result = qone({ list: list }).query("\n from a in list \n where !((a.isBaby && a.name='qone') && a.age = 28)\n select a\n ");
458 |
459 | assert.deepEqual(result, [{ "name": "qone", "age": 1, "isBaby": true }, { "name": "linq", "age": 18 }, { "name": "dntzhang", "age": 28 }]);
460 | });
461 |
462 | QUnit.test("Bool condition 12", function (assert) {
463 |
464 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
465 |
466 | var result = qone({ list: list }).query("\n from a in list \n where !((a.isBaby && a.name='qone') && ((a.age = 28)||!a.isBaby))\n select a\n ");
467 |
468 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }]);
469 | });
470 |
471 | QUnit.test("Bool condition 13", function (assert) {
472 |
473 | var list = [{ name: 'qone', age: 1, isBaby: true }, { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }];
474 |
475 | var result = qone({ list: list }).query("\n from a in list \n where ((a.isBaby && a.name='qone') && !((a.age = 28)||!a.isBaby))\n select a\n ");
476 |
477 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }]);
478 | });
479 |
480 | QUnit.test("Method test", function (assert) {
481 |
482 | var list = [{ name: 'qone', age: 1, scores: [1, 2, 3] }, { name: 'linq', age: 18, scores: [11, 2, 3] }, { name: 'dntzhang', age: 28, scores: [100, 2, 3] }];
483 |
484 | qone('fullCredit', function (item) {
485 | return item[0] === 100;
486 | });
487 |
488 | var result = qone({ list: list }).query("\n from a in list \n where fullCredit(a.scores)\n select a\n ");
489 |
490 | assert.deepEqual(result, [{ name: 'dntzhang', age: 28, scores: [100, 2, 3] }]);
491 | });
492 |
493 | QUnit.test("Access array", function (assert) {
494 |
495 | var list = [{ name: 'qone', age: 1, scores: [1, 2, 3] }, { name: 'linq', age: 18, scores: [11, 2, 3] }, { name: 'dntzhang', age: 28, scores: [100, 2, 3] }];
496 |
497 | var result = qone({ list: list }).query("\n from a in list \n where a.scores[0] === 100\n select a\n ");
498 |
499 | assert.deepEqual(result, [{ name: 'dntzhang', age: 28, scores: [100, 2, 3] }]);
500 | });
501 |
502 | QUnit.test("Access array", function (assert) {
503 |
504 | var list = [{ name: 'qone', age: 1, scores: [{ a: 1 }, 2, 3] }, { name: 'linq', age: 18, scores: [{ a: 2 }, 2, 3] }, { name: 'dntzhang', age: 28, scores: [{ a: 3 }, 2, 3] }];
505 |
506 | var result = qone({ list: list }).query("\n from a in list \n where a.scores[0].a === 3\n select a\n ");
507 |
508 | assert.deepEqual(result, [{ name: 'dntzhang', age: 28, scores: [{ a: 3 }, 2, 3] }]);
509 | });
510 |
511 | QUnit.test("Access array", function (assert) {
512 |
513 | var list = [{ name: 'qone', age: 1, scores: [[1, 2], 2, 3] }, { name: 'linq', age: 18, scores: [[3, 4], 2, 3] }, { name: 'dntzhang', age: 28, scores: [[5, 6], 2, 3] }];
514 |
515 | var result = qone({ list: list }).query("\n from a in list \n where a.scores[0][1] === 6\n select a\n ");
516 |
517 | assert.deepEqual(result, [{ name: 'dntzhang', age: 28, scores: [[5, 6], 2, 3] }]);
518 | });
519 |
520 | QUnit.test("Method test", function (assert) {
521 |
522 | var list = [{ name: 'qone', age: 1, scores: [1, 2, 3] }, { name: 'linq', age: 18, scores: [11, 2, 3] }, { name: 'dntzhang', age: 28, scores: [100, 2, 3] }];
523 |
524 | qone('fullCredit', function (item, x, y) {
525 | return item[0] * x + y === '22abc';
526 | });
527 |
528 | var result = qone({ list: list }).query("\n from a in list \n where fullCredit(a.scores, 2, \"abc\")\n select a\n ");
529 |
530 | assert.deepEqual(result, [{ name: 'linq', age: 18, scores: [11, 2, 3] }]);
531 | });
532 |
533 | QUnit.test("Single line test", function (assert) {
534 | 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 }];
535 |
536 | var result = qone({ list: list }).query('from n in list where n.age > 1 select n limit 1, 3');
537 |
538 | assert.deepEqual(result, [{ name: 'dntzhang3', age: 3 }, { name: 'dntzhang4', age: 4 }, { name: 'dntzhang5', age: 5 }]);
539 | });
540 |
541 | QUnit.test("Limit one page test", function (assert) {
542 | 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 }];
543 |
544 | var pageIndex = 1,
545 | pageSize = 4;
546 | var result = qone({ list: list }).query("\n from n in list \n where n.age > 0\n select n\n limit " + pageIndex * pageSize + ", " + pageSize + "\n ");
547 |
548 | assert.deepEqual(result, [{ name: 'dntzhang5', age: 5 }, { name: 'dntzhang6', age: 6 }, { name: 'dntzhang7', age: 7 }, { name: 'dntzhang8', age: 8 }]);
549 | });
550 |
551 | QUnit.test("Limit top 3", function (assert) {
552 | 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 }];
553 |
554 | var pageIndex = 1,
555 | pageSize = 4;
556 | var result = qone({ list: list }).query("\n from n in list \n select n\n limit 0, 3\n ");
557 |
558 | assert.deepEqual(result, [{ name: 'dntzhang1', age: 1 }, { name: 'dntzhang2', age: 2 }, { name: 'dntzhang3', age: 3 }]);
559 | });
560 |
561 | QUnit.test("Limit top 13", function (assert) {
562 | 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 }];
563 |
564 | var pageIndex = 1,
565 | pageSize = 4;
566 | var result = qone({ list: list }).query("\n from n in list \n select n\n limit 0, 13\n ");
567 |
568 | assert.deepEqual(result, [{ 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 }]);
569 | });
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 |
2 | QUnit.test("Basic test", function (assert) {
3 | var arr = [1, 2, 3, 4, 5]
4 |
5 | var result = qone({ arr }).query(`
6 | from n in arr
7 | where n > 3
8 | select n
9 | `)
10 |
11 | assert.deepEqual(result, [4, 5])
12 | })
13 |
14 | QUnit.test("Query json array", function (assert) {
15 | var list = [
16 | { name: 'qone', age: 1 },
17 | { name: 'linq', age: 18 },
18 | { name: 'dntzhang', age: 28 }
19 | ]
20 |
21 | var result = qone({ list }).query(`
22 | from n in list
23 | where n.age > 18
24 | select n
25 | `)
26 |
27 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
28 |
29 | })
30 |
31 | QUnit.test("Multi conditional query", function (assert) {
32 | var list = [
33 | { name: 'qone', age: 1 },
34 | { name: 'linq', age: 18 },
35 | { name: 'dntzhang', age: 28 }
36 | ]
37 |
38 | var result = qone({ list }).query(`
39 | from n in list
40 | where n.age > 10 && n.name = 'linq'
41 | select n
42 | `)
43 |
44 | assert.deepEqual(result, [{ "name": "linq", "age": 18 }])
45 |
46 | })
47 |
48 | QUnit.test("Select test", function (assert) {
49 | var list = [
50 | { name: 'qone', age: 1 },
51 | { name: 'linq', age: 18 },
52 | { name: 'dntzhang', age: 28 }
53 | ]
54 |
55 | var result = qone({ list }).query(`
56 | from n in list
57 | where n.age < 20
58 | select n.age, n.name
59 | `)
60 |
61 | assert.deepEqual(result, [[1, "qone"], [18, "linq"]])
62 |
63 | })
64 |
65 | QUnit.test("Select JSON test", function (assert) {
66 | var list = [
67 | { name: 'qone', age: 1 },
68 | { name: 'linq', age: 18 },
69 | { name: 'dntzhang', age: 28 }
70 | ]
71 |
72 | var result = qone({ list }).query(`
73 | from n in list
74 | where n.age < 20
75 | select {n.age, n.name}
76 | `)
77 |
78 | assert.deepEqual(result, [
79 | { "age": 1, "name": "qone" },
80 | { "age": 18, "name": "linq" }
81 | ])
82 |
83 | })
84 |
85 | QUnit.test("Select full JSON test", function (assert) {
86 | var list = [
87 | { name: 'qone', age: 1 },
88 | { name: 'linq', age: 18 },
89 | { name: 'dntzhang', age: 28 }
90 | ]
91 |
92 | var result = qone({ list }).query(`
93 | from n in list
94 | where n.age < 20
95 | select {a : n.age, b : n.name}
96 | `)
97 |
98 | assert.deepEqual(result, [
99 | { "a": 1, "b": "qone" },
100 | { "a": 18, "b": "linq" }
101 | ])
102 |
103 | })
104 |
105 | QUnit.test("|| conditional test", function (assert) {
106 | var list = [
107 | { name: 'qone', age: 1 },
108 | { name: 'linq', age: 18 },
109 | { name: 'dntzhang', age: 28 }
110 | ]
111 |
112 | var result = qone({ list }).query(`
113 | from n in list
114 | where n.age > 19 || n.age < 2
115 | select n
116 | `)
117 |
118 | assert.deepEqual(result, [
119 | { "name": "qone", "age": 1 },
120 | { "name": "dntzhang", "age": 28 }
121 | ])
122 |
123 | })
124 |
125 | QUnit.test("|| and && conditional test", function (assert) {
126 | var list = [
127 | { name: 'qone', age: 0 },
128 | { name: 'linq', age: 1 },
129 | { name: 'linq', age: 18 },
130 | { name: 'dntzhang', age: 28 }
131 | ]
132 |
133 | var result = qone({ list }).query(`
134 | from n in list
135 | where n.age > 17 || n.age < 2 && n.name != 'dntzhang'
136 | select n
137 | `)
138 |
139 | assert.deepEqual(result, [
140 | { "name": "qone", "age": 0 },
141 | { "name": "linq", "age": 1 },
142 | { "name": "linq", "age": 18 },
143 | { "name": "dntzhang", "age": 28 }])
144 |
145 | })
146 |
147 | QUnit.test("(), || and && conditional test", function (assert) {
148 | var list = [
149 | { name: 'qone', age: 0 },
150 | { name: 'linq', age: 1 },
151 | { name: 'linq', age: 18 },
152 | { name: 'dntzhang', age: 28 }
153 | ]
154 |
155 | var result = qone({ list }).query(`
156 | from n in list
157 | where (n.age > 17 || n.age < 2) && n.name != 'dntzhang'
158 | select n
159 | `)
160 |
161 | assert.deepEqual(result, [
162 | { "name": "qone", "age": 0 },
163 | { "name": "linq", "age": 1 },
164 | { "name": "linq", "age": 18 }])
165 |
166 | })
167 |
168 |
169 | QUnit.test("Query from prop", function (assert) {
170 | var data = {
171 | users: [
172 | { name: 'qone', age: 1 },
173 | { name: 'dntzhang', age: 17 },
174 | { name: 'dntzhang2', age: 27 }]
175 | }
176 |
177 | var result = qone({ data }).query(`
178 | from n in data.users
179 | where n.age < 10
180 | select n
181 | `)
182 |
183 | assert.deepEqual(result, [{ "name": "qone", "age": 1 }])
184 |
185 | })
186 |
187 |
188 | QUnit.test("Multi datasource ", function (assert) {
189 |
190 | var listA = [
191 | { name: 'qone', age: 1 },
192 | { name: 'linq', age: 18 },
193 | { name: 'dntzhang', age: 28 }]
194 |
195 |
196 | var listB = [
197 | { name: 'x', age: 11 },
198 | { name: 'xx', age: 12 },
199 | { name: 'xxx', age: 13 }
200 | ]
201 |
202 |
203 | var result = qone({ listA, listB }).query(`
204 | from a in listA
205 | from b in listB
206 | where a.age < 20 && b.age > 11
207 | select a, b
208 | `)
209 |
210 | assert.deepEqual(result, [
211 | [{ "name": "qone", "age": 1 }, { "name": "xx", "age": 12 }],
212 | [{ "name": "qone", "age": 1 }, { "name": "xxx", "age": 13 }],
213 | [{ "name": "linq", "age": 18 }, { "name": "xx", "age": 12 }],
214 | [{ "name": "linq", "age": 18 }, { "name": "xxx", "age": 13 }]])
215 | })
216 |
217 | QUnit.test("Multi datasource with props condition", function (assert) {
218 |
219 | var listA = [
220 | { name: 'qone', age: 1 },
221 | { name: 'linq', age: 18 },
222 | { name: 'dntzhang', age: 28 }]
223 |
224 |
225 | var listB = [
226 | { name: 'x', age: 11 },
227 | { name: 'xx', age: 18 },
228 | { name: 'xxx', age: 13 }
229 | ]
230 |
231 | var result = qone({ listA, listB }).query(`
232 | from a in listA
233 | from b in listB
234 | where a.age = b.age
235 | select a, b
236 | `)
237 |
238 | assert.deepEqual(result, [[{ "name": "linq", "age": 18 }, { "name": "xx", "age": 18 }]])
239 | })
240 |
241 | QUnit.test("Bool condition ", function (assert) {
242 |
243 | var list = [
244 | { name: 'qone', age: 1, isBaby: true },
245 | { name: 'linq', age: 18 },
246 | { name: 'dntzhang', age: 28 }]
247 |
248 | var result = qone({ list }).query(`
249 | from a in list
250 | where a.isBaby
251 | select a
252 | `)
253 |
254 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
255 | })
256 |
257 | QUnit.test("Bool condition ", function (assert) {
258 |
259 | var list = [
260 | { name: 'qone', age: 1, isBaby: [true] },
261 | { name: 'linq', age: 18, isBaby: [false] },
262 | { name: 'dntzhang', age: 28, isBaby: [false] }]
263 |
264 | var result = qone({ list }).query(`
265 | from a in list
266 | where a.isBaby[0]
267 | select a
268 | `)
269 |
270 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: [true] }])
271 | })
272 |
273 |
274 |
275 | QUnit.test("Multi from test ", function (assert) {
276 |
277 | var list = [
278 | { name: 'qone', age: 1, isBaby: true, colors: ['red', 'green', 'blue'] },
279 | { name: 'linq', age: 18, colors: ['red', 'blue'] },
280 | { name: 'dntzhang', age: 28, colors: ['red', 'blue'] }]
281 |
282 | var result = qone({ list }).query(`
283 | from a in list
284 | from c in a.colors
285 | where c = 'green'
286 | select a, c
287 | `)
288 |
289 | assert.deepEqual(result, [[{ "name": "qone", "age": 1, "isBaby": true, "colors": ["red", "green", "blue"] }, "green"]])
290 | })
291 |
292 |
293 |
294 |
295 | QUnit.test("Multi deep from test ", function (assert) {
296 |
297 | var list = [
298 | { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
299 | { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
300 | { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]
301 |
302 | var result = qone({ list }).query(`
303 | from a in list
304 | from c in a.colors
305 | from d in c.xx
306 | select a, c,d
307 | `)
308 |
309 | assert.equal(result.length, 18)
310 | })
311 |
312 |
313 | QUnit.test("Multi deep from test ", function (assert) {
314 |
315 | var list = [
316 | { name: 'qone', age: 1, isBaby: true, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] },
317 | { name: 'linq', age: 18, colors: [{ xx: [100, 2, 3] }, { xx: [11, 2, 3] }] },
318 | { name: 'dntzhang', age: 28, colors: [{ xx: [1, 2, 3] }, { xx: [11, 2, 3] }] }]
319 |
320 | var result = qone({ list }).query(`
321 | from a in list
322 | from c in a.colors
323 | from d in c.xx
324 | where d === 100
325 | select a.name, c,d
326 | `)
327 |
328 | assert.deepEqual(result, [["linq", { "xx": [100, 2, 3] }, 100]])
329 | })
330 |
331 | QUnit.test("Deep prop path test ", function (assert) {
332 |
333 | var list = [
334 | { name: 'qone', age: 1, fullName: { first: 'q', last: 'one' } },
335 | { name: 'linq', age: 18, fullName: { first: 'l', last: 'inq' } },
336 | { name: 'dntzhang', age: 28, fullName: { first: 'dnt', last: 'zhang' } }]
337 |
338 | var result = qone({ list }).query(`
339 | from a in list
340 | where a.fullName.first === 'dnt'
341 | select a.name
342 | `)
343 |
344 | assert.deepEqual(result, ["dntzhang"])
345 | })
346 |
347 |
348 | QUnit.test("Method test 1", function (assert) {
349 | var arr = [1, 2, 3, 4, 5]
350 |
351 | qone('square', function (num) {
352 | return num * num
353 | })
354 |
355 | var result = qone({ arr }).query(`
356 | from n in arr
357 | where square(n) > 10
358 | select n
359 | `)
360 |
361 | assert.deepEqual(result, [4, 5])
362 | })
363 |
364 |
365 | QUnit.test("Method test 2", function (assert) {
366 | var arr = [1, 2, 3, 4, 5]
367 |
368 | qone('square', function (num) {
369 | return num * num
370 | })
371 |
372 | var result = qone({ arr }).query(`
373 | from n in arr
374 | where 10 > square(n)
375 | select n
376 | `)
377 |
378 | assert.deepEqual(result, [1, 2, 3])
379 | })
380 |
381 |
382 | QUnit.test("Method test 3", function (assert) {
383 | var arr = [1, 2, 3, 4, 5]
384 |
385 | qone('square', function (num) {
386 | return num * num
387 | })
388 |
389 | var result = qone({ arr }).query(`
390 | from n in arr
391 | where n > 3
392 | select square(n)
393 | `)
394 |
395 | assert.deepEqual(result, [16, 25])
396 | })
397 |
398 | QUnit.test("Method test 4", function (assert) {
399 | var arr = [1, 2, 3, 4, 5]
400 |
401 | qone('square', function (num) {
402 | return num * num
403 | })
404 |
405 | var result = qone({ arr }).query(`
406 | from n in arr
407 | where n > 3
408 | select n, square(n)
409 | `)
410 |
411 | assert.deepEqual(result, [[4, 16], [5, 25]])
412 | })
413 |
414 |
415 | QUnit.test("Method test 5", function (assert) {
416 | var arr = [1, 2, 3, 4, 5]
417 |
418 | qone('square', function (num) {
419 | return num * num
420 | })
421 |
422 | var result = qone({ arr }).query(`
423 | from n in arr
424 | where n > 3
425 | select { value : n, squareValue : square(n) }
426 | `)
427 |
428 | assert.deepEqual(result, [
429 | { "value": 4, "squareValue": 16 },
430 | { "value": 5, "squareValue": 25 }])
431 | })
432 |
433 | QUnit.test("Method test 6", function (assert) {
434 | var arr = [1, 2, 3, 4, 5]
435 |
436 | qone('square', function (num) {
437 | return num * num
438 | })
439 |
440 | var result = qone({ arr }).query(`
441 | from n in arr
442 | where n > 3
443 | select { squareValue : square(n) }
444 | `)
445 |
446 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
447 | })
448 |
449 | QUnit.test("Method test 7", function (assert) {
450 | var arr = [1, 2, 3, 4, 5]
451 |
452 | qone('square', function (num) {
453 | return num * num
454 | })
455 |
456 | var result = qone({ arr }).query(`
457 | from n in arr
458 | where n > 3
459 | select { squareValue : square(n) }
460 | `)
461 |
462 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
463 | })
464 |
465 | QUnit.test("Method test 8", function (assert) {
466 | var arr = [1, 2, 3, 4, 5]
467 |
468 | qone('square', function (num) {
469 | return num * num
470 | })
471 |
472 | qone('sqrt', function (num) {
473 | return Math.sqrt(num)
474 | })
475 |
476 | var result = qone({ arr }).query(`
477 | from n in arr
478 | where sqrt(n) >= 2
479 | select { squareValue : square(n) }
480 | `)
481 |
482 | assert.deepEqual(result, [{ "squareValue": 16 }, { "squareValue": 25 }])
483 | })
484 |
485 | QUnit.test("Method test 9", function (assert) {
486 | var list = [
487 | { name: 'qone', age: 1 },
488 | { name: 'linq', age: 19 },
489 | { name: 'dntzhang', age: 28 }
490 | ]
491 |
492 | qone('greaterThan18', function (num) {
493 | return num > 18
494 | })
495 |
496 | var result = qone({ list }).query(`
497 | from n in list
498 | where greaterThan18(n.age) && n.name = 'dntzhang'
499 | select n
500 | `)
501 |
502 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
503 |
504 | })
505 |
506 | QUnit.test("Method test 10", function (assert) {
507 | var list = [
508 | { name: 'qone', age: 1 },
509 | { name: 'linq', age: 19 },
510 | { name: 'dntzhang', age: 28 }
511 | ]
512 |
513 | qone('greaterThan18', function (num) {
514 | return num > 18
515 | })
516 |
517 | var result = qone({ list }).query(`
518 | from n in list
519 | where greaterThan18(n.age) && n.name = 'dntzhang'
520 | select n
521 | `)
522 |
523 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
524 |
525 | })
526 |
527 | QUnit.test("Order by test 1", function (assert) {
528 | var list = [
529 | { name: 'linq2', age: 7 },
530 | { name: 'qone', age: 1 },
531 | { name: 'linq', age: 18 },
532 | { name: 'dntzhang', age: 28 }
533 | ]
534 |
535 | var result = qone({ list }).query(`
536 | from n in list
537 | where n.age > 0
538 | orderby n.age desc
539 | select n
540 | `)
541 |
542 | assert.deepEqual(result, [
543 | { "name": "dntzhang", "age": 28 },
544 | { "name": "linq", "age": 18 },
545 | { "name": "linq2", "age": 7 },
546 | { "name": "qone", "age": 1 }])
547 |
548 | })
549 |
550 | QUnit.test("Order by test 2", function (assert) {
551 | var list = [
552 | { name: 'linq2', age: 7 },
553 | { name: 'qone', age: 1 },
554 | { name: 'linq', age: 18 },
555 | { name: 'ainq', age: 18 },
556 | { name: 'dntzhang', age: 28 }
557 | ]
558 |
559 | var result = qone({ list }).query(`
560 | from n in list
561 | where n.age > 0
562 | orderby n.age asc, n.name desc
563 | select n
564 | `)
565 |
566 | assert.deepEqual(result, [
567 | { "name": "qone", "age": 1 },
568 | { "name": "linq2", "age": 7 },
569 | { "name": "linq", "age": 18 },
570 | { "name": "ainq", "age": 18 },
571 | { "name": "dntzhang", "age": 28 }])
572 |
573 | })
574 |
575 |
576 |
577 | QUnit.test("Order by test 3", function (assert) {
578 | var list = [
579 | { name: 'qone', age: 17, age2: 2 },
580 | { name: 'linq', age: 18, age2: 1 },
581 | { name: 'dntzhang1', age: 28, age2: 2 },
582 | { name: 'dntzhang2', age: 28, age2: 1 },
583 | { name: 'dntzhang3', age: 29, age2: 1 }
584 | ]
585 |
586 | qone('sum', function (a, b) {
587 | return a + b
588 | })
589 |
590 |
591 | var result = qone({ list }).query(`
592 | from n in list
593 | where n.age > 0
594 | orderby sum(n.age,n.age2)
595 | select n
596 | `)
597 |
598 | assert.deepEqual(result, [
599 | { name: 'qone', age: 17, age2: 2 },
600 | { name: 'linq', age: 18, age2: 1 },
601 | { name: 'dntzhang2', age: 28, age2: 1 },
602 | { name: 'dntzhang1', age: 28, age2: 2 },
603 | { name: 'dntzhang3', age: 29, age2: 1 }])
604 |
605 | })
606 |
607 |
608 | QUnit.test("Order by test 4", function (assert) {
609 | var list = [
610 | { name: 'qone', age: 17, age2: 2 },
611 | { name: 'linq', age: 18, age2: 1 },
612 | { name: 'dntzhang1', age: 28, age2: 2 },
613 | { name: 'dntzhang2', age: 28, age2: 1 },
614 | { name: 'dntzhang3', age: 29, age2: 1 }
615 | ]
616 |
617 | qone('sum', function (a, b) {
618 | return a + b
619 | })
620 |
621 |
622 | var result = qone({ list }).query(`
623 | from n in list
624 | where n.age > 0
625 | orderby sum(n.age,n.age2) ,n.name
626 | select n
627 | `)
628 |
629 | assert.deepEqual(result, [
630 | { name: 'linq', age: 18, age2: 1 },
631 | { name: 'qone', age: 17, age2: 2 },
632 |
633 | { name: 'dntzhang2', age: 28, age2: 1 },
634 | { name: 'dntzhang1', age: 28, age2: 2 },
635 | { name: 'dntzhang3', age: 29, age2: 1 }])
636 |
637 | })
638 |
639 | QUnit.test("Simple groupby test 1", function (assert) {
640 | var list = [
641 | { name: 'qone', age: 1 },
642 | { name: 'linq', age: 18 },
643 | { name: 'dntzhang1', age: 28 },
644 | { name: 'dntzhang2', age: 28 },
645 | { name: 'dntzhang3', age: 29 }
646 | ]
647 |
648 | var result = qone({ list }).query(`
649 | from n in list
650 | where n.age > 18
651 | groupby n.age
652 | `)
653 |
654 | assert.deepEqual(result, [
655 | [{ "name": "dntzhang1", "age": 28 }, { "name": "dntzhang2", "age": 28 }],
656 | [{ "name": "dntzhang3", "age": 29 }]])
657 |
658 | })
659 |
660 | QUnit.test("Simple groupby test 2", function (assert) {
661 | var list = [
662 | { name: 'qone', age: 1 },
663 | { name: 'qone', age: 1 },
664 | { name: 'dntzhang', age: 28 },
665 | { name: 'dntzhang2', age: 28 },
666 | { name: 'dntzhang', age: 29 }
667 | ]
668 |
669 | var result = qone({ list }).query(`
670 | from n in list
671 | where n.age > 0
672 | groupby n.age,n.name
673 | `)
674 |
675 | assert.deepEqual(result, [
676 | [{ "name": "qone", "age": 1 }, { "name": "qone", "age": 1 }],
677 | [{ "name": "dntzhang", "age": 28 }],
678 | [{ "name": "dntzhang2", "age": 28 }],
679 | [{ "name": "dntzhang", "age": 29 }]])
680 |
681 | })
682 |
683 | QUnit.test("Simple groupby with method", function (assert) {
684 | var list = [
685 | { name: 'qone', age: 17, age2: 2 },
686 | { name: 'linq', age: 18, age2: 1 },
687 | { name: 'dntzhang1', age: 28, age2: 1 },
688 | { name: 'dntzhang2', age: 28, age2: 1 },
689 | { name: 'dntzhang3', age: 29, age2: 1 }
690 | ]
691 | qone('sum', function (a, b) {
692 | return a + b
693 | })
694 |
695 |
696 | var result = qone({ list }).query(`
697 | from n in list
698 | groupby sum(n.age,n.age2)
699 | `)
700 |
701 | assert.deepEqual(result, [
702 | [{ name: 'qone', age: 17, age2: 2 }, { name: 'linq', age: 18, age2: 1 }],
703 | [{ name: 'dntzhang1', age: 28, age2: 1 }, { name: 'dntzhang2', age: 28, age2: 1 }],
704 | [{ name: 'dntzhang3', age: 29, age2: 1 }]])
705 |
706 | })
707 |
708 |
709 | QUnit.test("Simple groupby with method", function (assert) {
710 | var list = [
711 | { name: 'qone', age: 17, age2: 2 },
712 | { name: 'qone', age: 18, age2: 1 },
713 | { name: 'dntzhang1', age: 28, age2: 1 },
714 | { name: 'dntzhang2', age: 28, age2: 1 },
715 | { name: 'dntzhang3', age: 29, age2: 1 }
716 | ]
717 | qone('sum', function (a, b) {
718 | return a + b
719 | })
720 |
721 |
722 | var result = qone({ list }).query(`
723 | from n in list
724 | groupby sum(n.age,n.age2), n.name
725 | `)
726 |
727 | assert.deepEqual(result, [
728 | [{ name: 'qone', age: 17, age2: 2 }, { name: 'qone', age: 18, age2: 1 }],
729 | [{ name: 'dntzhang1', age: 28, age2: 1 }],
730 | [{ name: 'dntzhang2', age: 28, age2: 1 }],
731 | [{ name: 'dntzhang3', age: 29, age2: 1 }]])
732 |
733 | })
734 |
735 | QUnit.test("Bool condition 1 ", function (assert) {
736 |
737 | var list = [
738 | { name: 'qone', age: 1, isBaby: true },
739 | { name: 'linq', age: 18 },
740 | { name: 'dntzhang', age: 28 }]
741 |
742 | var result = qone({ list }).query(`
743 | from a in list
744 | where !a.isBaby
745 | select a
746 | `)
747 |
748 | assert.deepEqual(result, [
749 | { "name": "linq", "age": 18 },
750 | { "name": "dntzhang", "age": 28 }])
751 | })
752 |
753 |
754 |
755 | QUnit.test("Bool condition 2 ", function (assert) {
756 |
757 | var list = [
758 | { name: 'qone', age: 1, isBaby: true },
759 | { name: 'linq', age: 18 },
760 | { name: 'dntzhang', age: 28 }]
761 |
762 | var result = qone({ list }).query(`
763 | from a in list
764 | where !a.isBaby && a.name='qone'
765 | select a
766 | `)
767 |
768 | assert.deepEqual(result, [])
769 | })
770 |
771 |
772 | QUnit.test("Bool condition 3 ", function (assert) {
773 |
774 | var list = [
775 | { name: 'qone', age: 1, isBaby: true },
776 | { name: 'linq', age: 18 },
777 | { name: 'dntzhang', age: 28 }]
778 |
779 | var result = qone({ list }).query(`
780 | from a in list
781 | where !(a.isBaby && a.name='qone')
782 | select a
783 | `)
784 |
785 |
786 | assert.deepEqual(result, [{ name: 'linq', age: 18 }, { "name": "dntzhang", "age": 28 }])
787 | })
788 |
789 |
790 | QUnit.test("Bool condition 4 ", function (assert) {
791 |
792 | var list = [
793 | { name: 'qone', age: 1, isBaby: true },
794 | { name: 'linq', age: 18 },
795 | { name: 'dntzhang', age: 28 }]
796 |
797 | var result = qone({ list }).query(`
798 | from a in list
799 | where !(a.isBaby && a.name='qone') && a.age = 28
800 | select a
801 | `)
802 |
803 |
804 | assert.deepEqual(result, [{ "name": "dntzhang", "age": 28 }])
805 | })
806 |
807 |
808 | QUnit.test("Bool condition 5 ", function (assert) {
809 |
810 | var list = [
811 | { name: 'qone', age: 1, isBaby: true },
812 | { name: 'linq', age: 18 },
813 | { name: 'dntzhang', age: 28 }]
814 |
815 | var result = qone({ list }).query(`
816 | from a in list
817 | where a.isBaby = true
818 | select a
819 | `)
820 |
821 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
822 | })
823 |
824 |
825 |
826 | QUnit.test("Bool condition 6 ", function (assert) {
827 |
828 | var list = [
829 | { name: 'qone', age: 1, isBaby: true },
830 | { name: 'linq', age: 18 },
831 | { name: 'dntzhang', age: 28 }]
832 |
833 | var result = qone({ list }).query(`
834 | from a in list
835 | where a.isBaby = true
836 | select a
837 | `)
838 |
839 | assert.deepEqual(result, [{ name: 'qone', age: 1, isBaby: true }])
840 | })
841 |
842 | QUnit.test("Bool condition 7 ", function (assert) {
843 |
844 | var list = [
845 | { name: 'qone', age: 1, isBaby: true },
846 | { name: 'linq', age: 18 },
847 | { name: 'dntzhang', age: 28 }]
848 |
849 | var result = qone({ list }).query(`
850 | from a in list
851 | where a.isBaby = true
852 | select a
853 | `)
854 |
855 | assert.deepEqual(result, [
856 | { name: 'qone', age: 1, isBaby: true }])
857 | })
858 |
859 | QUnit.test("Bool condition 8 ", function (assert) {
860 |
861 | var list = [
862 | { name: 'qone', age: 1, isBaby: true },
863 | { name: 'linq', age: 18 },
864 | { name: 'dntzhang', age: 28 }]
865 |
866 | var result = qone({ list }).query(`
867 | from a in list
868 | where a.isBaby = undefined
869 | select a
870 | `)
871 |
872 | assert.deepEqual(result, [
873 | { name: 'linq', age: 18 }, { name: 'dntzhang', age: 28 }])
874 | })
875 |
876 | QUnit.test("Bool condition 9 ", function (assert) {
877 |
878 | var list = [
879 | { name: 'qone', age: 1, isBaby: true },
880 | { name: 'linq', age: 18, isBaby: false },
881 | { name: 'dntzhang', age: 28, isBaby: false }]
882 |
883 | var result = qone({ list }).query(`
884 | from a in list
885 | where a.isBaby = false
886 | select a
887 | `)
888 |
889 | assert.deepEqual(result, [
890 | { name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: false }])
891 | })
892 |
893 | QUnit.test("Bool condition 10 ", function (assert) {
894 |
895 | var list = [
896 | { name: 'qone', age: 1, isBaby: true },
897 | { name: 'linq', age: 18, isBaby: false },
898 | { name: 'dntzhang', age: 28, isBaby: null }]
899 |
900 | var result = qone({ list }).query(`
901 | from a in list
902 | where a.isBaby = false || a.isBaby = null
903 | select a
904 | `)
905 |
906 | assert.deepEqual(result, [
907 | { name: 'linq', age: 18, isBaby: false }, { name: 'dntzhang', age: 28, isBaby: null }])
908 | })
909 |
910 | QUnit.test("Bool condition 11 ", function (assert) {
911 |
912 | var list = [
913 | { name: 'qone', age: 1, isBaby: true },
914 | { name: 'linq', age: 18 },
915 | { name: 'dntzhang', age: 28 }]
916 |
917 | var result = qone({ list }).query(`
918 | from a in list
919 | where !((a.isBaby && a.name='qone') && a.age = 28)
920 | select a
921 | `)
922 |
923 | assert.deepEqual(result, [
924 | { "name": "qone", "age": 1, "isBaby": true },
925 | { "name": "linq", "age": 18 },
926 | { "name": "dntzhang", "age": 28 }])
927 | })
928 |
929 |
930 | QUnit.test("Bool condition 12", function (assert) {
931 |
932 | var list = [
933 | { name: 'qone', age: 1, isBaby: true },
934 | { name: 'linq', age: 18 },
935 | { name: 'dntzhang', age: 28 }]
936 |
937 | var result = qone({ list }).query(`
938 | from a in list
939 | where !((a.isBaby && a.name='qone') && ((a.age = 28)||!a.isBaby))
940 | select a
941 | `)
942 |
943 | assert.deepEqual(result, [
944 | { name: 'qone', age: 1, isBaby: true },
945 | { name: 'linq', age: 18 },
946 | { name: 'dntzhang', age: 28 }])
947 | })
948 |
949 |
950 | QUnit.test("Bool condition 13", function (assert) {
951 |
952 | var list = [
953 | { name: 'qone', age: 1, isBaby: true },
954 | { name: 'linq', age: 18 },
955 | { name: 'dntzhang', age: 28 }]
956 |
957 | var result = qone({ list }).query(`
958 | from a in list
959 | where ((a.isBaby && a.name='qone') && !((a.age = 28)||!a.isBaby))
960 | select a
961 | `)
962 |
963 | assert.deepEqual(result, [
964 | { name: 'qone', age: 1, isBaby: true }])
965 | })
966 |
967 |
968 | QUnit.test("Method test", function (assert) {
969 |
970 | var list = [
971 | { name: 'qone', age: 1, scores: [1, 2, 3] },
972 | { name: 'linq', age: 18, scores: [11, 2, 3] },
973 | { name: 'dntzhang', age: 28, scores: [100, 2, 3] }]
974 |
975 | qone('fullCredit', function (item) {
976 | return item[0] === 100
977 | })
978 |
979 | var result = qone({ list }).query(`
980 | from a in list
981 | where fullCredit(a.scores)
982 | select a
983 | `)
984 |
985 | assert.deepEqual(result, [
986 | { name: 'dntzhang', age: 28, scores: [100, 2, 3] }])
987 | })
988 |
989 |
990 | QUnit.test("Access array", function (assert) {
991 |
992 | var list = [
993 | { name: 'qone', age: 1, scores: [1, 2, 3] },
994 | { name: 'linq', age: 18, scores: [11, 2, 3] },
995 | { name: 'dntzhang', age: 28, scores: [100, 2, 3] }]
996 |
997 |
998 | var result = qone({ list }).query(`
999 | from a in list
1000 | where a.scores[0] === 100
1001 | select a
1002 | `)
1003 |
1004 | assert.deepEqual(result, [
1005 | { name: 'dntzhang', age: 28, scores: [100, 2, 3] }])
1006 | })
1007 |
1008 | QUnit.test("Access array", function (assert) {
1009 |
1010 | var list = [
1011 | { name: 'qone', age: 1, scores: [{ a: 1 }, 2, 3] },
1012 | { name: 'linq', age: 18, scores: [{ a: 2 }, 2, 3] },
1013 | { name: 'dntzhang', age: 28, scores: [{ a: 3 }, 2, 3] }]
1014 |
1015 |
1016 | var result = qone({ list }).query(`
1017 | from a in list
1018 | where a.scores[0].a === 3
1019 | select a
1020 | `)
1021 |
1022 | assert.deepEqual(result, [
1023 | { name: 'dntzhang', age: 28, scores: [{ a: 3 }, 2, 3] }])
1024 | })
1025 |
1026 |
1027 | QUnit.test("Access array", function (assert) {
1028 |
1029 | var list = [
1030 | { name: 'qone', age: 1, scores: [[1, 2], 2, 3] },
1031 | { name: 'linq', age: 18, scores: [[3, 4], 2, 3] },
1032 | { name: 'dntzhang', age: 28, scores: [[5, 6], 2, 3] }]
1033 |
1034 |
1035 | var result = qone({ list }).query(`
1036 | from a in list
1037 | where a.scores[0][1] === 6
1038 | select a
1039 | `)
1040 |
1041 | assert.deepEqual(result, [
1042 | { name: 'dntzhang', age: 28, scores: [[5, 6], 2, 3] }])
1043 | })
1044 |
1045 |
1046 | QUnit.test("Method test", function (assert) {
1047 |
1048 | var list = [
1049 | { name: 'qone', age: 1, scores: [1, 2, 3] },
1050 | { name: 'linq', age: 18, scores: [11, 2, 3] },
1051 | { name: 'dntzhang', age: 28, scores: [100, 2, 3] }]
1052 |
1053 | qone('fullCredit', function (item, x, y) {
1054 | return item[0] * x + y === '22abc'
1055 | })
1056 |
1057 | var result = qone({ list }).query(`
1058 | from a in list
1059 | where fullCredit(a.scores, 2, "abc")
1060 | select a
1061 | `)
1062 |
1063 | assert.deepEqual(result, [
1064 | { name: 'linq', age: 18, scores: [11, 2, 3] }])
1065 | })
1066 |
1067 |
1068 | QUnit.test("Single line test", function (assert) {
1069 | var list = [
1070 | { name: 'dntzhang1', age: 1 },
1071 | { name: 'dntzhang2', age: 2 },
1072 | { name: 'dntzhang3', age: 3 },
1073 | { name: 'dntzhang4', age: 4 },
1074 | { name: 'dntzhang5', age: 5 },
1075 | { name: 'dntzhang6', age: 6 },
1076 | { name: 'dntzhang7', age: 7 },
1077 | { name: 'dntzhang8', age: 8 },
1078 | { name: 'dntzhang9', age: 9 },
1079 | { name: 'dntzhang10', age: 10 }
1080 |
1081 | ]
1082 |
1083 | var result = qone({ list }).query('from n in list where n.age > 1 select n limit 1, 3')
1084 |
1085 |
1086 | assert.deepEqual(result, [
1087 | { name: 'dntzhang3', age: 3 },
1088 | { name: 'dntzhang4', age: 4 },
1089 | { name: 'dntzhang5', age: 5 }])
1090 |
1091 | })
1092 |
1093 |
1094 | QUnit.test("Limit one page test", function (assert) {
1095 | var list = [
1096 | { name: 'dntzhang1', age: 1 },
1097 | { name: 'dntzhang2', age: 2 },
1098 | { name: 'dntzhang3', age: 3 },
1099 | { name: 'dntzhang4', age: 4 },
1100 | { name: 'dntzhang5', age: 5 },
1101 | { name: 'dntzhang6', age: 6 },
1102 | { name: 'dntzhang7', age: 7 },
1103 | { name: 'dntzhang8', age: 8 },
1104 | { name: 'dntzhang9', age: 9 },
1105 | { name: 'dntzhang10', age: 10 }
1106 | ]
1107 |
1108 | var pageIndex = 1,
1109 | pageSize = 4
1110 | var result = qone({ list }).query(`
1111 | from n in list
1112 | where n.age > 0
1113 | select n
1114 | limit ${pageIndex * pageSize}, ${pageSize}
1115 | `)
1116 |
1117 |
1118 | assert.deepEqual(result, [{ name: 'dntzhang5', age: 5 },
1119 | { name: 'dntzhang6', age: 6 },
1120 | { name: 'dntzhang7', age: 7 },
1121 | { name: 'dntzhang8', age: 8 }])
1122 |
1123 | })
1124 |
1125 |
1126 | QUnit.test("Limit top 3", function (assert) {
1127 | var list = [
1128 | { name: 'dntzhang1', age: 1 },
1129 | { name: 'dntzhang2', age: 2 },
1130 | { name: 'dntzhang3', age: 3 },
1131 | { name: 'dntzhang4', age: 4 },
1132 | { name: 'dntzhang5', age: 5 },
1133 | { name: 'dntzhang6', age: 6 },
1134 | { name: 'dntzhang7', age: 7 },
1135 | { name: 'dntzhang8', age: 8 },
1136 | { name: 'dntzhang9', age: 9 },
1137 | { name: 'dntzhang10', age: 10 }
1138 | ]
1139 |
1140 | var pageIndex = 1,
1141 | pageSize = 4
1142 | var result = qone({ list }).query(`
1143 | from n in list
1144 | select n
1145 | limit 0, 3
1146 | `)
1147 |
1148 |
1149 | assert.deepEqual(result, [
1150 |
1151 | { name: 'dntzhang1', age: 1 },
1152 | { name: 'dntzhang2', age: 2 },
1153 | { name: 'dntzhang3', age: 3 }
1154 | ])
1155 |
1156 | })
1157 |
1158 |
1159 |
1160 |
1161 | QUnit.test("Limit top 13", function (assert) {
1162 | var list = [
1163 | { name: 'dntzhang1', age: 1 },
1164 | { name: 'dntzhang2', age: 2 },
1165 | { name: 'dntzhang3', age: 3 },
1166 | { name: 'dntzhang4', age: 4 },
1167 | { name: 'dntzhang5', age: 5 },
1168 | { name: 'dntzhang6', age: 6 },
1169 | { name: 'dntzhang7', age: 7 },
1170 | { name: 'dntzhang8', age: 8 },
1171 | { name: 'dntzhang9', age: 9 },
1172 | { name: 'dntzhang10', age: 10 }
1173 | ]
1174 |
1175 | var pageIndex = 1,
1176 | pageSize = 4
1177 | var result = qone({ list }).query(`
1178 | from n in list
1179 | select n
1180 | limit 0, 13
1181 | `)
1182 |
1183 |
1184 | assert.deepEqual(result, [
1185 |
1186 | { name: 'dntzhang1', age: 1 },
1187 | { name: 'dntzhang2', age: 2 },
1188 | { name: 'dntzhang3', age: 3 },
1189 | { name: 'dntzhang4', age: 4 },
1190 | { name: 'dntzhang5', age: 5 },
1191 | { name: 'dntzhang6', age: 6 },
1192 | { name: 'dntzhang7', age: 7 },
1193 | { name: 'dntzhang8', age: 8 },
1194 | { name: 'dntzhang9', age: 9 },
1195 | { name: 'dntzhang10', age: 10 }
1196 | ])
1197 |
1198 | })
--------------------------------------------------------------------------------