值域
值域是一种隔离机制。例如:同样名称的参数可以出现在不同的 域
里,在 DataQL 中一共有三个可以用的值域符号:
$
值域符#
值域符@
值域符
tip
DataQL 的值域,在没有明确分别它们的时候。三个访问符的值域内容是没有任何区别的。
值域符的应用场景只有两个
- 值域参数隔离
- 表达式访问符
值域参数隔离
获取程序传入的参数必须使用:<访问符>{<参数名>}
方式来获取。这个特性类似带参的SQL,例如:
用不同值域隔离同名参数的例子
// 创建一个 Map 为每个值域中都放入不同变量,但是变量名都是 'a'
Map<String, Map<String, Object>> objectMap = new HashMap<>();
objectMap.put("#", new HashMap<String, Object>() {{
put("a", 1);
}});
objectMap.put("$", new HashMap<String, Object>() {{
put("a", 2);
}});
objectMap.put("@", new HashMap<String, Object>() {{
put("a", 3);
}});
然后通过 Query 接口创建查询并执行查询(通过 CustomizeScope
接口来返回不同访问符的数据 Map)
${abc}、@{abc}、#{abc} 三个值域
DataQL dataQL = ...
Query query = dataQL.createQuery("return [#{a},${a},@{a}];");
DataModel dataModel = query.execute(new CustomizeScope() {
public Map<String, ?> findCustomizeEnvironment(String symbol) {
return objectMap.get(symbol);
}
}).getData();
查询结果
[1, 2, 3]
表达式访问符
表达式访问符同样使用了 @
、#
、$
三个符号,在表达式中的访问符是指类似如下的取值表达式:
$ss.sss.sss
#ss[abc].sss.sss
@abc.abc(true).sss
表达式中的访问符不同含义如下:
$
表示环境栈根#
表示环境栈顶@
表示整个环境栈(数组形态)
要理解这种带有访问符的含义需要理解 DataQL 的运行模式,DataQL 的运行时模型和 JVM 有些类似。
不同的是 DataQL 采用的是两栈一堆。比 JVM 堆栈模型多了一个 环境栈
。
- 环境栈
- 运行栈(作用和 JVM 相似)
- 数据堆(作用和 JVM 相似)
查询过程中一般情况下环境栈始终是空的,当遇到 =>
操作时。
DataQL 会把 =>
符左边的表达式值放入环境栈,当转换结束时 DataQL 会把表达式值从环境栈中删掉。
如果在转换过程中遇到第二次 =>
操作,那么会在环境栈顶中放入新的数据。例如:下面这个查询就会出现双层环境栈
一个DataQL查询
var data = {
"userInfo" : {
"username" : "xxxxx",
"password" : "pass"
},
"basicInfo" : {
"name" : "马三",
"sex" : "F"
},
"id" : 12345667
}
return data => { // 第一次出现
"userInfo" : userInfo => { // 第二次出现
"username",
"password",
"userId" : $.id
},
"name" : basicInfo.name // 这种形式不会出现
}
执行结果为
{
"userInfo":{
"username":"xxxxx",
"password":"pass",
"userId":12345667
},
"name":"马三"
}
tip
所有表达式在编译的时都会有一个访问符,如果用户没有指定那么将会使用 #
作为默认访问符。
即便所有表达式在编译之后都具有访问符,但这并不代表数据的源头都来自环境栈。编译器会优先在本地变量表中查找。具体逻辑在 NameRouteVariableInstCompiler
类中。
例如:如下例子,在对一颗 Tree
进行结构变换时。希望每一层都能带上 parentID
。
样本数据
[
{
"id": 1,
"label": "t1",
"children": [
{
"id": 2,
"label": "t2",
"children": [
{
"id": 4,
"label": "t4",
"children": []
}
]
},
{
"id": 3,
"label": "t3",
"children": []
}
]
},
{
"id": 5,
"label": "t5",
"children": []
}
]
DataQL 查询
var treeData = ..// 样本数据
var treeFmt = (dat) -> {
return {
"id" : dat.id,
"parent_id": ((@[-3] !=null)? @[-3].id : null), // 获取整个环境栈然后在倒数第三层上获取
"label" : dat.label,
"children" : dat.children => [ treeFmt(#) ]
}
}
return treeData => [ treeFmt(#) ]
参照数据 @[-3]
含义如下: