-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] 语法设计上的一些建议和思考 #584
Comments
你好,感谢你的关注。 所有能自动化的前提一定是标准化,而且不能有 歧义/矛盾/冲突 的地方。 1、操作符使用简化简化后会有歧义,和 = 冲突。id 不一定是主键名,类型不一定是 int,可能是 varchar 等,简化后会导致冲突等各种问题。 没有任何地方可以省略作为 IN 或者 条件 的操作符 {},只不过是 "key>=" 这种换了功能符来替代而已。 "id{}": [82001, 82002] // id IN(82001, 82002),表示在一个选项范围
"id{}": "<30,>=100" // id <30 OR id >=100,表示在一个条件范围 @ 符号不能省,还是歧义与冲突问题,省一个字符的工作量几乎没有意义,反而导致各种问题。 @column, @order 等 @key , @ 在前面表示关键词,和字段名等区分开来,类比微信聊天、GitHub 评论等各种场景, "@luo-zhan" 并不是单纯 "@" 和 "luo-zhan" 的组合,而是带有 用户标识,甚至可点击跳转的超链接 等的特殊 字符串片段。 2、符号的语义化APIJSON 用 $ 表示 Search,$ 和 S 很像,对应 SQL 的 LIKE。各种关系型数据库基本都有 LIKE 语法,例如 name LIKE '%a%' 表示 name 包含 a,tag LIKE 'b%' 表示从 b 开始等,%, _ 都是 LIKE 语法的通配符。 APIJSON 早期用 "key?": "^[0-9]+$" 这种 ? 结尾表示 value 为正则表达式,但后面看到 PostgreSQL 用 ~ 表示正则语法,就改为了 ~。 ~ 用于 100~200 这种范围,确实接近平常在数学上的语法,之前也考虑过,不过已经用于正则了。 "key%": "100,200" 表示 key BETWEEN 100 AND 200,没有哪个符号比 % 更能直观形象地表示夹在两个值中间的 BETWEEN AND 语法了。"key%":["100,200", "500,1000"] 表示 key BETWEEN 100 AND 200 OR key BETWEEN 500 AND 1000,一开始实现是 "key%": [100, 200] 表示 key BETWEEN 100 AND 200,但为了多个条件,以及和 "key$":["a%", "b%", "%c%" ] 统一,更方便记忆,所以改成了目前的方式,当然对于 PostgreSQL 等,需要传参 "@cast": "date%:DATE", "date%": "2020-01-01,2022-01-01" 来 CAST('2020-01-01' AS DATE),不过也可以 URI 传参 stringtype=unspecified 支持传字符串,数据库自动转为对应的 DATE 等类型。 "key{}": [1, 2, 3],用 "{}" 表示 IN 来源于 Java 等语言中定义数组的语法: int[] arr = new int[]{1, 2, 3} 就是用 {} 包含数组元素。EXIST 和 IN 功能接近,经常被放在一块讨论,所以就把符号反过来 }{ 作为 EXISTS,}{ 本身也看起来像 X,也像 E 的正反两面左右拼起来,删除一个字符 } 并没有显著增加工作量。/ 已经用与 key 路径分隔符,不能在 key 中包含,否则就会解析引用赋值路径 User/id, []/Moment/id 等出错,除非转义,但转义成 %2F 甚至有的地方转移成 %252F 显然不是好的方式。key}{ 中的 key 只是在所属对象中的一个唯一标识,只要不和其它 key 同名即可。EXISTS(SELECT id FROM sys.Comemnt WHERE toId=0) ,一般建议 "toId}{@":{ "from": "Comment", "Comment":{"@column": "id", "toId": 0 } } 更直观表示是 toId 相关的子查询,当然把 "toId}{" 换成 "anyKey}{" 在功能使用上也没有任何问题。 "key<>": 1 ,用 "{}" 表示 IN 来源于 Java 等语言中定义集合泛型的语法: List<Integer> list = new ArrayList<>(); List 可包含类型为 Integer 的元素。 3、API 使用简化"from":"Comment" 是为了方便解析,性能也更好。去掉的话是能实现,就像 "[]":{ "Comment":{} } 遍历即可,但不划算,毕竟子查询用得少,多打一个键值对也没增加大的工作量。另外子查询内部也可以使用 JOIN,传多个表对象。 去掉 @ 等一个字符,带来歧义、冲突等各种问题,很不划算,就像是用 位运算、冷门语法 减少几行代码,难以理解导致可维护性差,况且这里 APIJSON 仅仅是节省一个字符的而已,还没有代码中 冷门语法 带来的提升明显。 后续如果新增一些新的功能,例如 "contactIdList<>": 82001 表示 json_contains(contactIdList, '$', 82001),位置固定为最外层, 如果需要自定义位置,可以 "structure<>": {
"path": "$.User.contactIdList"
"value": 82001
} 表示 json_contains(structure, '$.User.contactIdList', 82001) "structure<>": {
} 就只能表示 json_contains(structure, 子查询),不能这样扩展功能了。 感谢你的关注和贡献意愿,开源仅靠少数个人的力量是远远不够的,要大家一起参与才能可持续发展,欢迎为 APIJSON 贡献~ |
APIJSON 规划及路线图 建议收集箱 关于新增功能、优化性能等的一些想法 |
很认同你说的语法设计要做到没有歧义和冲突,我想表达的是避免冲突的前提下尽量简化使用。 1.看了回复之后我发现我之前有个误解,我原以为 'id%': '1,10'
'id{}': '>=1,<=10' ps. 2.关于范围查询符号
// 简单查询
'id': 1
'id': [1,2] // in
'id!': [1,2] // not in
'id>': 5
'id%': "1,5"
// 复杂查询使用{}
'id{}': '>10,<=5,[7,8,9,10]' 这样设计应该不会有冲突问题,使用更简单,而且上手文档中很容易表达清楚。 3. // js
var a = 'Hello';
var b = `${a}`; #!/bin/bash
a=Hello
b=$a 如果觉得放在value中会引起冲突,可以设计成非引用时通过 'id': '@[]/Moment/id' //引用
'user_id': '\@luozhan' // 等于 即使退一万步讲因为种种原因没法放在value中,也建议换一个符号, 4.存在操作符使用 5.“ 这里其实可以同时兼容写from和不写from的情况啊,不写from就自动判断拿第一个表名字段就好了,在大多数情况下写起来是简单的、符合直觉的,这样前期上手根本不需要了解from字段,遇到复杂情况再找找from用法就好。(这点性能损失可以忽略,再说咱也不是主打性能,既然是提高开发效率为目的的框架,使用体验会更重要~) ps.这里的from不也是内置字段吗,为啥不用加‘@’符号呢? 最后,其实所有想法想表达的就是一点:降低上手难度,好的设计应该是大部分情况直接就能用,当遇到复杂情况再查查文档,顺便学习一下加深映像,整个学习曲线是平滑的。 语法设计要做到没有歧义不难,但同时还能简化用法、符合用户直觉就比较难了,语法复杂就会带来更高的学习成本,也同时带来更高的解释成本(写文档和回答问题),都阻碍这个优秀框架的流行。 |
1."key{}": String 可以实现各种复杂条件,有 SQL 函数则不拼接 key,没有就拼接:例如 "key!{}":"%2=0;length(key)>5;date_diff(key,now())<=7" 对应 SQL: NOT(key %2=0 OR length(key)>5 OR date_diff(key,now())<=7) 没有完整的替代方案,所以仍会保留 2.以上已经说明歧义和冲突,符号必须保留,不要想当然觉得 id 这个字段名就一定是主键,类型一定是 int/varchar。 3.仍然是歧义和冲突问题,通用编程语言功能强大复杂,转义可以理解,但 Java 都不支持直接这样写,而是必须调函数 String.format 等来解析占位符。 4.上面已经恢复了,APIJSON 用 / 作为路径分隔符,如果是 "id/": {
"Comment": {},
"User": {
"id@": "id//Comment/userId" // 注意即写成相对路径 /Comment/userId 也会自动补全为前面的绝对路径
}
} 会误解析为 ["id", "", "Comment", "userId"] "id/@": {
"Comment": {},
"User": {
"id@": "id//Comment/userId" // 注意即写成相对路径 /Comment/userId 也会自动补全为前面的绝对路径
}
} 会误解析为 ["id", "@", "Comment", "userId"] 改成 @exist 虽然确实能让理解成本低些,但多个 EXISTS 就得传数组套对象 "@exist": [{
"Moment": {}
}, {
"Comment": {},
"User": {
"id@": "/Comment/userId"
}
}
...
] 或者两层对象嵌套了 "@exist": {
"momentId{}": {
"Moment": {}
},
"commentId>": {
"Comment": {},
"User": {
"id@": "/Comment/userId"
}
}
...
} 还不如现在的方式简单 "momentId{}@": {
"Moment": {}
},
"commentId>@": {
"Comment": {},
"User": {
"id@": "/Comment/userId"
}
} 5.from 可以通过扫描 符合表名的 key 且 value 为 JSONObject 类型来改为不传。 https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L386-L394 @ 符号是为了和对象内其它容易混淆的字段名等做区分,避免重名,很难混淆的地方就尽量不加,例如: 都不加 @,因为几乎不可能有冲突,这些地方一般不会有自定义字段,即便有也能轻松避免同名冲突, |
新增支持子查询对象内省略关键词 from,自动取最上方的表对象 key 作为 from |
过了几天再来看,发现已经看不懂你回复里面的EXISTS 语法和截图里面的 |
Description
作者你好,这是我第二次接触Apijson了,半年前被复杂的操作符和学习成本劝退,但是设计思想是一直比较吸引人,直到最近有机会再次深入阅读了一次文档,发现了项目很多的闪光点,但是对于包括我在内的一些觉得Apijson的学习门槛有点高的情况有一些个人建议。
1、操作符使用简化
Apijson中常用的筛选条件类型包括:
Apijson的语法在筛选条件的使用方式上有点不一致,比方说
in
和>=
都是列名后加{}
表示指定筛选条件,但是在一些情况下又可以忽略{}
:当遇到逻辑运算时,操作符看起来更复杂(比列名还长...)
关联查询本质也是等于,但是需要列名后加
@
符号,此时也不用加{}
以上,在类似的场景下,使用方式却各不相同,不太简单直观
建议
可以去掉
{}
并统一等值筛选的语法,因等值筛选使用频率很高,采用最简单的设计:ps.关联查询的
@
符号和Apijson的关键词前缀@
是冲突的,对于新手来说就会经常遇到@
符号一会在前一会在后,容易产生疑惑,这也是另一个不建议关联查询的@
符号放在key中的原因2、符号的语义化
Apijson的设计规则是
列名+操作符+值
,另一个上手难度就是在操作符的功能定义上,其中+
、-
、>
、<
、&
、|
、!
、@
的定义是完全ok的,基本没有学习成本,而$
、~
、?
、%
、{}
、<>
、}{
的定义就还有设计余地,导致学习成本比较高(比方我看了两遍文档了还是不能准确快速的背下来...)以下摘取自官方文档:
建议
不知道作者对上述操作符的选取有没有特别的用意,如果有的话建议写在文档里加强使用者的记忆,降低学习成本,下面是我个人的一些想法,可供参考。
like查询
可以使用
?
代表不确定的结果、模糊的含义,表示模糊查询。正则查询
使用正则表达式开头的符号
^
作为操作符,比较好记ps.这里我再多提一点想法:
正则查询和like查询都是模糊查询,如果两者能使用
?
的话对新手上手是最友好的,所以如果更看重用户体验,可以考虑就用?
表示模糊查询,然后通过value值是否包含%
来判定是like查询还是正则查询但是这样会存在一个bug——如果正则表达式中有
%
则会被误判,此时就要求开发者必须使用^
符号明确指定是正则查询了,考虑到大多数开发者应该会偏向于使用其中某一种查询方式,而另外一种查询很少会用(像我们团队就几乎不用正则查询),那这种特殊情况在文档中标注清楚解决办法就好,不算大问题。这样就既对新手友好,又能符合功能需求,可以考虑一下。
范围查询
一般范围是两个值,比如日期范围
“1992~2023”
,金额范围“100~999”
,使用~
就非常直观另外既然范围是两个值,value使用方括号可读性可能会更好(不过这个不是必须,个人感觉都行)
筛选 {}
这个操作符和其他单字符操作符不同,是两个字符拼成的,其实会对使用者的体验造成割裂的。建议都是用单字符操作符。
在筛选操作符这里,个人感觉
{}
可以省略掉,像上述几种查询方式都是筛选,但只有在in条件和多个比较条件时才需要使用{}
,有点奇怪的,不知道是不是有实现上的难点无法去除,还是有别的设计原因我没发现的,希望能不吝赐教,再探讨一下。json包含
<>
这个操作符也是两个字符的,建议使用单字符(
就好,括号有包括之意,也像字母Contain的首字母C
,方便记忆这样和json操作符增加、减少元素的使用体验上,也更加和谐一些:
存在 }{
必须要吐槽一下这个符号的设计实在是太奇怪了,在官方示例中配合
@
一起使用时,甚至给人一种乱码的既视感😂"id}{@"
而且在某些输入法下,输入
{
就会自动打出一对括号{}
,就导致输入}{
时,总是要手动删除输入法自动打出来的右大括号:}{}
→}{
这个符号因为使用场景应该也不会太多,建议换个冷门符号,比如
/
,记忆方法就类似湖南/中国
,只有中国存在才会有湖南,也不难记忆。ps.
id/
后的@
符号也去掉了,因为存在场景应该只有子查询一种情况吧,是不是必然有@符号,那么就不如省略掉(如果还有其他使用场景希望指正~)pss.我对这个id字段的意义还是比较疑惑,文档中说
这个id用来标识是哪个判断
,并不是很清晰,希望能解答一下,谢谢。3、Api使用简化
在下例中,
Comment
已经作为key了,那么能否省略使用from
再指定的一次:希望的使用方式:
还是说有什么别的设计原因?
类似的,“子查询相关比较”希望的使用方式:
上面都是基于我作为新手来阅读上手指南的一些感受和思考,可能有很多因为我的不够了解所以想当然了,但是确实是初次使用时的真实感受,相信也有很多初学者跟我有一样的想法,如果我的一些疑惑能解决,后续再放到上手指南中,对后来者也有所帮助,所以希望能和作者进一步的探讨。
Apijson确实是个有创意且强大的框架,如果在使用体验和上手指南上更进一步就更好了。如果有需要的话我也愿意帮助完善上手指南文档,让初学者更轻松的学习这个优秀的框架:D
The text was updated successfully, but these errors were encountered: