Operand是MOQL语法结构的重要组成部分,语法结构中那些需要被分析处理的数据列或数据值都被称之为Operand。如select后跟的数据列,where条件中描述的条件字段以及需要匹配的常数值等都被称之为Operand。如下面语句中的红色字体部分,均表示是一个Operand。通过对其计算,我们可以获得数据结果,并形成最终我们求解的数据结果集。
在MOQL中,Operand不仅能在完整的语法结构中使用,还可以单独使用。MOQL提供了方法可以直接创建一个操作数,并利用此操作数完成数据的求解。如下:
该例中为表达式"(num *num1) / num2 * 2.2 + 2 - 1"创建了一个操作数,该操作数利用传入的实体Map对表达式进行了求解,并输出了执行结果,结果为20.8。MoqlUtils的createOperand方法可以创建一个操作数,传给该方法的参数为一个操作数表达式字符串,返回的对象为一个Operand接口,该接口位于org.moql的包路径下,定义如下:
getOperandType()方法用于返回Operand的类型OperandType。OperandType为枚举类型,也位于org.moql的包路径下,定义格式如下:
其包括的Operand类型有常量(CONSTANT)、变量(VARIABLE)、函数(FUNCTION)、表达式(EXPRESSION)及列筛选器(COLUMNSELECTOR)五类(注:Operand的类型将在后面详细介绍),当Operand不属于以上任何一类时用UNKNOWN未知表示。
getName()方法用于获得Operand的名字。除了函数类型的Operand的名字为函数名外,其它类型的Operand的名字就是生成Operand的字符串本身。如:“sum(a.num)”整体被解析为一个函数Operand,其名字为“sum”,其内嵌了一个由“a.num”解析而成的表达式Operand作为参数,该Operand名字为“a.num”;再如:“123”被解析为常量Operand,其名字为“123”等。
getSource()方法用于返回操作数在文本串中的位置。如:“sum(a.num)”会被解析为多个操作数,对每个操作数调用该方法就可以定位操作数在文本串中的位置了。
operate(EntityMapentityMap)方法是Operand提供的主要方法,利用该方法操作数可以对给定的参数进行求值。EntityMap是一个装有实体对象的Map,其实体名若与变量Operand的名字一致,那么实体对象便会被变量Operand绑定用来求解。
booleanOperate(EntityMapentityMap)方法是operate(EntityMap entityMap)方法的扩展。用于将Operand的计算结果以布尔值的形式返回。若operate方法返回值的类型是java.lang.Boolean,则该方法返回调用Boolean.booleanValue()所得的值;若operate方法返回值的类型不是java.lang.Boolean,返回值为null时,返回false,否则返回true;
isConstantReturn()方法用于告诉调用者在调用Operand的operate方法后是否总能返回一个不变得常量值。若该Operand是一个常量类型的Operand,则该调用总是返回true,表示调用常量类型Operand的operate方法总是返回同一个常量值。而对于该方法更有意义的用途是在函数类型Operand以及表达式类型Operand中的调用。这两种类型的Operand在初始化时会判断所有其相关的Operand的该方法调用,返回是否都是true。若都是true,则表示该操作数的执行结果与operate调用时传入的EntityMap参数无关,那么就可以预先对该操作数进行求解,而不用等到每次调用operate方法时现去求解了。这样可以在一定程度上提升Operand的执行效率。若对该方法的调用感兴趣,可以查看源代码中
reset()方法用于重置Operand,将Operand的状态恢复为初始状态。Operand在计算时分为有状态和无状态两种情况。有状态是指当对Operand的operate方法进行多次调用时,其计算结果受以前调用结果的影响;而无状态是指多次调用不会受以前调用结果的影响。对于有状态的Operand需要通过调用reset方法将其状态恢复为初始状态。如:“sum(a.num)”对应的Operand,会累计每次调用operate方法的结果,对每次调用的值求和。若需要重新开始计数,需要调用reset方法将该Operand恢复为初始值。类似的Operand还有count、avg、max、min等聚合函数。
常量Operand
Operand支持的常量类型包括字符串型(String)、双浮点型(Double)、长整型(Long)以及NULL类型。
字符串Operand的格式与SQL中字符串的格式一致。字符串的两端需要用单引号(‘)包围,如:’String’、’字符串’、’123’、’123.1’、’null’等都表示字符串。当字符串中也需要包含单引号(‘)时,也完全遵从SQL字符串的约束,用两个相连的单引号(‘’)来表示一个字符串中的单引号如:’Str’’ing’其代表的字符串为”Str’ing”。
双浮点Operand可以表示的数据范围与Java语言中的java.lang.Double对象可以表示的数据范围一致。它可以覆盖浮点型(float)数据的数据范围。MOQL中所有浮点数都以双浮点Operand表示,如:123.4、-12.78、23.3e15等。
长整型Operand表示的数据范围与Java语言中的java.lang.Long对象所表示的数据范围一致。在MOQL中SQL语法支持的byte、short、integer以及long类型都以长整型Operand表示。另外长整型Operand还支持八进制、十进制以及十六进制的数据格式,如:19、3435L、0xAFCD、-1235、072等。
NULL类型Operand用来表示null。其只有null这一种表现形式,所有字母必须是纯小写。
常量Operand的代码示例如下:
其执行结果输出如下:
字符串Null未被解析为NULL类型的常量Operand,而是被解析为了变量类型的Operand。
变量Operand
变量类型Operand的命名规范与Java语法中变量的标示符的命名规范一致。其标示符通常是以大小写英文字母、数字、下划线“_”和美元符号“$”组成,其中数字不能成为标示符的首字母。另外,标示符的命名也支持汉语的文字或其它语言的语言的文字,如:_data、a1、$a、长度、num等。
变量Operand的示例代码如下:
其执行结果输出如下:
函数Operand
函数Operand的格式如下:函数名(参数1,参数2…)。函数名与Java语法中标示符的命名规范一致,该命名规范已在变量Operand中进行了描述。其每一个参数都是一个Operand,Operand可以是常量、变量、函数或者表达式中的任意一种。如:sum(a)、_formatTime(‘yyyy-mm-dd’,getCurrentTime())、random(23+15)等。
函数Operand的示例代码如下:
其执行结果输出如下:
MOQL目前已支持了部分的函数Operand,如聚集函数Operand:count、sum、avg、min、以及max等。这些Operand在生成后调用operate方法就可以直接对数据进行计算。但如果要创建一个MOQL未支持的函数,MOQL会为其创建一个缺省的Operand,该Operand只是对函数字符串进行了解析,如上面的代码片段中的函数“test(1, num, 'a')”。该函数字符串被解析为一个缺省的函数Operand,但是当我们调用它的operate方法时,它会抛出一个java.lang.UnsupportedOperationException,表示该Operand不支持该方法。为了能够让MOQL也支持test函数,我们需要为test做一个对应的Operand的实现。相关的实现代码如下:
其执行结果输出如下:
从上例代码的执行情况我们看到,在第一次创建test函数的Operand后,调用operate方法抛出了异常;于是在第二次创建test函数的Operand前,我们调用了MOQL的函数注册方法,为test函数注册了Operand的实现类Test。而后我们创建了test函数的Operand并调用了它的operate方法。此次调用获得了预期的输出效果。其根本原因是,第一次创建的函数Operand,因未找到注册的Operand实现,生成了一个缺省的函数Operand,该Operand不支持operate方法;而第二次我们创建函数Operand时,发现了注册的实现类Test,于是绑定了该实现,生成了test函数对应的Operand。
表达式Operand
表达式Operand是MOQL语法中格式最丰富且复杂的一类、。它包括数组表达式、数学运算表达式以及成员表达式三种类型。另外,在MOQL源代码中我们还可以看到,表达式Operand至少还包括关系运算表达式以及逻辑运算表达式。但这两种表达式无法通过MoqlUtils.createOperand()直接创建,它们必须应用在过滤器(Filter)中。我们将在过滤器(Filter)中介绍以上两种表达式的应用。
数组表达式Operand
数组表达式Operand除了能对传统意义上的数组进行描述定义外,还可以对如:Map、List等集合进行定义描述。其基本的格式为:“数组对象[索引]”。数组对象可以是一个变量、数组表达式或成员表达式Operand;索引可以是一个常量、变量、函数或表达式Operand。
数组表达式Operand中的数组对象不仅仅包括Java语言中所有调用isArray()方法返回true的数组对象,还包括所有实现了java.lang.Iterable接口和java.util.Map接口的对象,以及java.sql.ResultSet对象和org.moql.RecordSet对象。ResultSet与RecordSet分别是JDBC查询和MOQL查询的结果对象。数组对象中除了实现了java.util.Map接口的对象外,其他所有对象都是以数值索引方式进行访问的,且都是以‘’作为数组中第一个数据的索引。若索引不是以数值形式传入,而是以字符串形式传入的,系统会尝试将该字符串转换为一个数值索引后,再进行数组访问,如array[1]、array[‘1’]等。而实现了java.util.Map接口的对象,其索引可以为任意对象,该对象即这个Map对象的Key,如:map[‘key’]。若数组表达式的索引值没有填写,如:array[],则除Map对象外表示要访问数组中的全部数据,而Map对象表示要访问其全部值数据,不包括Key数据。
数组表达式Operand的相关示例代码如下:
其执行结果如下:
数学运算表达式Operand
数学运算表达式Operand的格式如下:“Operand1运算符Operand2”。数学运算表达式支持的数学运算符都是二元运算符,他们按执行的优先顺序划分为:乘法(*)、除法(/)、模(%)优于加法(+)、减法(-)优于按位与(&)优于异或(^)优于按位或(|)运算。运算符两端的两个操作数可以是除列筛选Operand以外的任意类型的Operand。若其中一个Operand是另一个数学运算表达式Operand,则整个表达式就是一个包含连续多个运算符操作的表达式,如:a + 1 * 10 / 5等。
数学运算表达式Operand的相关示例代码如下:
其执行结果如下:
成员表达式Operand
成员表达式Operand用于访问对象的成员属性或者成员函数。其格式如下:“对象.成员”。“.”是成员运算符,其左侧的对象可以是变量、函数、数组表达式或成员表达式Operand;其右侧的成员可以是变量或函数Operand。当成员是变量Operand时,“对象”必须拥有能够获得该变量的对应的Getter函数。当变量是布尔型时,函数名为变量加上”is”前缀;当变量是非布尔型时,函数名为变量加上”get”前缀。当成员是函数Operand时,“对象”必须拥有对应的函数,且函数的参数类型需要与函数Operand中描述的参数类型一致。
成员表达式Operand的相关示例代码如下:
其执行结果如下:
列筛选Operand
列筛选Operand是一类特殊的Operand,该类Operand无法通过MoqlUtils的createOperand方法直接创建。它的格式为一个只返回一个字段的MOQL查询语句,如:select field1 from table where field2
项目地址:https://github.com/colorknight/moql
领取专属 10元无门槛券
私享最新 技术干货