Tencent / APIJSON

🏆 实时 零代码、全功能、强安全 ORM 库 🚀 后端接口和文档零代码,前端(客户端) 定制返回 JSON 的数据和结构 🏆 Real-Time coding-free, powerful and secure ORM 🚀 providing APIs and Docs without coding by Backend, and the returned JSON of API can be customized by Frontend(Client) users
http://apijson.cn
Other
17.1k stars 2.14k forks source link

apijson json服务编排 #482

Open cloudAndMonkey opened 1 year ago

cloudAndMonkey commented 1 year ago

Description

@TommyLemon 功能描述: 一个服务编排的伪码流程设计 将伪码转换为 apijson json、前置、后置函数、javascript、redis、elasticSearch等 并且能够mork每一步,执行中间流程,还能查询每个阶段执行的sql语句,及结果.

json格式:

{
    "@transaction": true, 
    "id@-()": "getCurrentUserId()", // 前置函数
    "@post": [
        "xxx"
    ], 
    "xxx": {
     "@method": "xxx",
      "@version": "", // 版本,控制校验
      "@datasource": "" // 数据源相关配置
     // 分表规则等,后面再说
   }
"@explain": true
}

1、独立定义一个url method, 通过解析不同method执行不同流程 和已有method区分开,避免歧义 2、最外层新增传参 "transaction": true 来指定开启事务 3、控制每条语句的数据源 4、完善 “@Explain" 如果没有执行计划,则返回sql语句. 能够在 reponse返回值中, 看到json中执行的每条sql,方便排错 5、@version支持 定义不同场景的 新增、修改、删除等执行规则. 请通过version版本区分 6、前置函数 1) 要能拿到其他数据源 2) 能拿到json执行过程中的数据 3) 拿到当前数据源(和外部json一个事物执行) 4) 从数据库/或其他数据源 查询获取对照关系 组装数据, 调用对应数据源的api方法执行即可 5) 前置函数,能调用其他函数 把一些计算, 执行,计算 等 放到一个函数进行整合 还没细化 7、支持mork 通过伪码,分解为不同 阶段 的json语句执行

测试点: 1、测试 一个json多条语句,后置函数啥时候执行 2、操作其他数据源, 事物是json执行完才会提交, 需要保证一致性 3、redis、elasticSearch、javascript、lua等功能测试

cloudAndMonkey commented 1 year ago

@TommyLemon 1、独立定义一个url method, 通过解析不同method执行不同流程 和已有method区分开,避免歧义 对,这样更好,enum RequestMethod.java 新增 CRUD 这个枚举值,对应 URL 为 /crud,对于前端没传参 transaction: true 时自动放入 transaction: true。

场景: method= crud 1、传递 "@transaction": true 2、不传 这里实现方案要考虑几个点: 1、在校验模块, 遍历json每个对象、数组的 method, 就知道是否需要开启事物 但是 为了后面 函数调用支持事物, 这个方式有局限性 2、对应 URL 为 /crud,对于前端没传参 transaction: true 时自动放入 transaction: true 3、将不同method功能区分开 现在json执行是通用解析,需不需要控制, 只能调用crud 方法,才能支持增删改查等操作. 其他method, 除了函数、子查询,就只能和 url method保持一致的操作

TommyLemon commented 1 year ago

1、在校验模块, 遍历json每个对象、数组的 method, 就知道是否需要开启事物

扫描所有字段来识别是否有 transaction 代价太大了。 没有 transaction: true,那就不做全局事务处理,局部有 增删改 就局部处理事务。 如果业务需求必须整体有事务,那就通过 Request 表配置规则来强制 PUT transaction: true。

非 CRUD 方法,都只能和 URL method 完全一致,避免意料之外的安全风险。 如果传了 method 相关键值对("@delete":"Comment" 等),直接抛异常 "不支持在 GET 中 DELETE !"

话说现有使用方式 "@delete":["Comment"] 麻烦了点,前端传参应该尽可能简化,除非有兼容等严重问题或实现代价太大,APIJSON 所有 key 不支持逗号 , 分号 ; 斜杠 / 反斜杠 \,所以 "@delete":"Comment[],Moment" 并不会有兼容问题。 可以用 StringUtil.split 分割逗号,内部处理了整体空值、局部空值等。

cloudAndMonkey commented 1 year ago

@TommyLemon 1、扫描所有字段来识别是否有 transaction 代价太大了。 要考虑数组的情况, 不可行. 我当时就是不想全部解析, 只通过key及@变量 2、事物这块 那就通过 Request 表配置规则来强制 PUT transaction: true。 不需要, 每条执行语句都知道它的method 我先测一下 3、 "@delete":["Comment"] 我来改一下, 当时采用数组, 是想到后台直接jsonArray转换方便 4、非 CRUD 方法,都只能和 URL method 完全一致,避免意料之外的安全风险。 如果传了 method 相关键值对("@delete":"Comment" 等),直接抛异常 "不支持在 GET 中 DELETE !"

TommyLemon commented 1 year ago

为了支持跨数据源的事务,需要在 AbstractParser 新增一个

// Map<数据源标识, SQLExecutor 实例>
Map<String, SQLExecutor> datasourceSQLExecutorMap

数据源标识同 AbstractSQLExecutor.connectionMap 的 key https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractSQLExecutor.java#L1135-L1156

image

AbstractParser.getSQLExecutor 根据 数据源标识 get 到非 null 就返回,没有才 createSQLExecutor 然后 put 进 map 再返回; https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L344-L349

image

Parser.begin 时只对当前的 SQLExecutor 调用 begin。

Parser.rollback 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 rollback; Parser.commit 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 commit; Parser.close 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 close;

https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractParser.java#L1971-L1994

image
cloudAndMonkey commented 1 year ago

1、在校验模块, 遍历json每个对象、数组的 method, 就知道是否需要开启事物

扫描所有字段来识别是否有 transaction 代价太大了。 没有 transaction: true,那就不做全局事务处理,局部有 增删改 就局部处理事务。 如果业务需求必须整体有事务,那就通过 Request 表配置规则来强制 PUT transaction: true。

非 CRUD 方法,都只能和 URL method 完全一致,避免意料之外的安全风险。 如果传了 method 相关键值对("@delete":"Comment" 等),直接抛异常 "不支持在 GET 中 DELETE !"

话说现有使用方式 "@delete":["Comment"] 麻烦了点,前端传参应该尽可能简化,除非有兼容等严重问题或实现代价太大,APIJSON 所有 key 不支持逗号 , 分号 ; 斜杠 / 反斜杠 \,所以 "@delete":"Comment[],Moment" 并不会有兼容问题。 可以用 StringUtil.split 分割逗号,内部处理了整体空值、局部空值等。

@TommyLemon 1、全局事物这块 没有 transaction: true,那就不做全局事务处理,局部有 增删改 就局部处理事务。 不好意思, 这里我没有理解你的意思. 说说我的理解哈 json配置 datasource, 是知道哪些操作共享一个 datasource. 同一个数据源, 多个 PUT、DELETE、POST 使用同一个Connection. 也就是说, 只要一个 connection, 存在 PUT、DELETE、POST,就开启全局事物? 不好意思, 还是你更优的解决方案,我没有get到? image image commit 提交事物: 是在多个 操作( PUT、DELETE、POST ) 执行完, 才调用: image

TommyLemon commented 1 year ago

如果不是全局事务,那就只有当执行 增/删/改 时开启,执行完马上 commit,碰到下一个 增/删/改 再开启和 commit。 如果是全局事务,则一开始就开启,执行完整个请求再 commit。

cloudAndMonkey commented 1 year ago

@TommyLemon 这几点我已经搞好了 1、url method crud支持

解析顺序

1) 对象内 "@method" 2) "@post","@put","@delete" 3) 对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法 第三点不适用了,url method =crud,必须显示定义操作方法 throw new IllegalArgumentException("url crud方法,必须定义 " + key + " 对应的method, 例如: @post: \"xxx,xxx[]\" 或者 对象内 @method=\"POST\" !"); image

2、非 CRUD 方法,都只能和 URL method 完全一致,避免意料之外的安全风险。 如果传了 method 相关键值对("@delete":"Comment" 等),直接抛异常 "不支持在 GET 中 DELETE !" http://xxx/put

{
    "@post": "User:aa",
    "User:aa":{
        "username":"test-3",
        "password": "233223",
        "state": 1
    },
    "tag": "User",
    "@explain": true
}

image 3、非crud 支持函数、sql@ 子查询调用. 4、修改 "@get": 数组 改为 字符串

{
   "@post": "User:aa,User_address[]",
   "User:aa":{
        "username":"test1",
        "password": "123456",
        "state": 1
    },
    "User_address[]": [
        {
        "user_id@": "User:aa/id",
        "addr": "ddd",
        "count": 1
        },
        {
        "user_id@": "User:aa/id",
        "addr": "ddd1",
        "count": 2
        }
    ],
    "@delete": "User:delUser,User_address:delUserAddress",
    "User:delUser":{
        "id{}": ["b6d7c307-cb82-4780-8361-2509973d88de", "c63d7bd8-cbb8-41f8-9ee0-713f0d30474b","cadeca84-2901-4850-aa36-6672d9d34299"]
    },
    "User_address:delUserAddress": {
        "id{}": ["887edfe9-0206-415d-96de-325d97e248cb", "24eb9e05-d3ef-4661-8d22-c063643f61cd"]
    },
    "@explain": true
}

image

cloudAndMonkey commented 1 year ago

@TommyLemon 还有一个功能需要支持, put, 能够按照 name="xxx" 来修改.例如 update xxx set xxx ="" wehre name = "xxx" 目前非id put修改,只能通过ref引用做为条件进行修改,例如: // 非id修改

{
    "sql@": {
        "@method": "GET",
        "with": true,
        "from": "User",
        "User": {
          "@column": "username",
          "username": "非id-update-test-0"
        }
    },
    "User": {
        "@state": 1,
        "password": "123456",
        "username{}@": "sql"
    },
    "explan": true
}
WITH  `sql` AS (SELECT `username` FROM `housekeeping`.`User` WHERE  (  (`username` = '非id-update-test-0')  ) ) 
UPDATE `housekeeping`.`User` SET `password` = '123456_1669605075502' WHERE  (  (`username` IN ( SELECT * FROM `sql`) )  ) 

你看这么改行不? 对象内的临时变量 @xxx 作为条件, 例如 :

"User": {
        "@state": 1,
        "password": "123456"
    }
update user set password = "123456" where state = 1;
TommyLemon commented 1 year ago

@TommyLemon 这几点我已经搞好了 1、url method crud支持

解析顺序

  1. 对象内 "@method"
  2. "@post","@put","@delete"
  3. 对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法 第三点不适用了,url method =crud,必须显示定义操作方法 throw new IllegalArgumentException("url crud方法,必须定义 " + key + " 对应的method, 例如: @post: "xxx,xxx[]" 或者 对象内 @method="POST" !"); image

2、非 CRUD 方法,都只能和 URL method 完全一致,避免意料之外的安全风险。 如果传了 method 相关键值对("@delete":"Comment" 等),直接抛异常 "不支持在 GET 中 DELETE !" http://xxx/put { "@post": "User:aa", "User:aa":{ "username":"test-3", "password": "233223", "state": 1 }, "tag": "User", "@Explain": true } image 3、非crud 支持函数、sql@ 子查询调用. 4、修改 "@get": 数组 改为 字符串 { "@post": "User:aa,User_address[]", "User:aa":{ "username":"test1", "password": "123456", "state": 1 }, "User_address[]": [ { "user_id@": "User:aa/id", "addr": "ddd", "count": 1 }, { "user_id@": "User:aa/id", "addr": "ddd1", "count": 2 } ], "@delete": "User:delUser,User_address:delUserAddress", "User:delUser":{ "id{}": ["b6d7c307-cb82-4780-8361-2509973d88de", "c63d7bd8-cbb8-41f8-9ee0-713f0d30474b","cadeca84-2901-4850-aa36-6672d9d34299"] }, "User_address:delUserAddress": { "id{}": ["887edfe9-0206-415d-96de-325d97e248cb", "24eb9e05-d3ef-4661-8d22-c063643f61cd"] }, "@Explain": true } image

CRUD 方法,没有声明就用 GET。 @method 看起来已经没有必要了,可以考虑去掉。

TommyLemon commented 1 year ago
WITH  `sql` AS (SELECT `username` FROM `housekeeping`.`User` WHERE  (  (`username` = '非id-update-test-0')  ) ) 

@state 会被认为是自定义关键词,与现有语法冲突,不合适。 目前可以用 "@combine":"state" 指定 "state": 1 是条件。 https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2

image

https://github.com/Tencent/APIJSON/issues/277 https://github.com/Tencent/APIJSON/issues/425

cloudAndMonkey commented 1 year ago
WITH  `sql` AS (SELECT `username` FROM `housekeeping`.`User` WHERE  (  (`username` = '非id-update-test-0')  ) ) 

@State 会被认为是自定义关键词,与现有语法冲突,不合适。 目前可以用 "@combine":"state" 指定 "state": 1 是条件。 https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2 image

277 #425

嗯嗯,不好意思, 应该先查文档 测了一下,没问题, 转换为了regexp_like 正则匹配

{
    "User": {
        "state~": "1",
        "password": "123456",
        "username~": "test4",
        "@combine": "state~ & username~"
    },
    "explan": true
}
UPDATE `housekeeping`.`User` SET `password` = '123456_1669608632896' WHERE ( regexp_like(`state`, '1', 'c') ) AND ( regexp_like(`username`, 'test4', 'c') )
cloudAndMonkey commented 1 year ago

CRUD 方法,没有声明就用 GET。 @method 看起来已经没有必要了,可以考虑去掉。

@TommyLemon CRUD 方法,没有声明就用 GET。 会出现吞并 json执行语句, 返回200的情况. 不方便排错. 框架是"正确"执行, 但是 对于用户来说, 就是一种"错觉" 这也是我很想避免的情况 比如: http://xxx/crud

{
   "User:aa":{
        "username":"test1",
        "password": "123456",
        "state": 1
    },
    "User_address[]": [
        {
        "user_id@": "User:aa/id",
        "addr": "ddd",
        "count": 1
        },
        {
        "user_id@": "User:aa/id",
        "addr": "ddd1",
        "count": 2
        }
    ],
    "@put": "User_address:modifUA",
    "User_address:modifUA": 
    {
        "id": "5e2d528c-106a-4f14-90b2-f27b5943e3e1",
        "user_id@": "User:aa/id",
        "addr": "addr-01",
        "count": 1
    },

    "@explain": true
}

image

TommyLemon commented 1 year ago
        "username~": "test4",

带有查询条件功能符的话,不用声明在 @combine 内,也会作为条件

cloudAndMonkey commented 1 year ago

json 不用传递 @method, 代码我已经调整 我也做了head 子查询sql@的兼容,避免子查询别转化为 count执行 错误语句:

WITH  `sql` AS (SELECT count(*) FROM `housekeeping`.`Sys_user_role` WHERE  (  (`user_id` = '4732209c-5785-4827-b532-5092f154fd94')  ) ) \nSELECT * FROM `housekeeping`.`Sys_role` WHERE  (  (`id` IN ( SELECT * FROM `sql`) )  )  LIMIT 1

正确语句:

WITH  `sql` AS (SELECT `role_id` FROM `housekeeping`.`Sys_user_role` WHERE  (  (`user_id` = '4732209c-5785-4827-b532-5092f154fd94')  ) ) \nSELECT * FROM `housekeeping`.`Sys_role` WHERE  (  (`id` IN ( SELECT * FROM `sql`) )  )  LIMIT 1
TommyLemon commented 1 year ago

CRUD 方法,没有声明就用 GET。 @method 看起来已经没有必要了,可以考虑去掉。

@TommyLemon CRUD 方法,没有声明就用 GET。 会出现吞并 json执行语句, 返回200的情况. 不方便排错. 框架是"正确"执行, 但是 对于用户来说, 就是一种"错觉" 这也是我很想避免的情况 比如: http://xxx/crud

{
   "User:aa":{
        "username":"test1",
        "password": "123456",
      "state": 1
    },
    "User_address[]": [
      {
      "user_id@": "User:aa/id",
      "addr": "ddd",
      "count": 1
      },
      {
      "user_id@": "User:aa/id",
      "addr": "ddd1",
      "count": 2
      }
    ],
    "@put": "User_address:modifUA",
    "User_address:modifUA": 
  {
      "id": "5e2d528c-106a-4f14-90b2-f27b5943e3e1",
      "user_id@": "User:aa/id",
      "addr": "addr-01",
      "count": 1
  },

    "@explain": true
}

image

未显示声明 method,默认用 GET,至于参数被吞掉,没有实际执行,这是 bug,改掉就好了

cloudAndMonkey commented 1 year ago

CRUD 方法,没有声明就用 GET。 @method 看起来已经没有必要了,可以考虑去掉。

@TommyLemon CRUD 方法,没有声明就用 GET。 会出现吞并 json执行语句, 返回200的情况. 不方便排错. 框架是"正确"执行, 但是 对于用户来说, 就是一种"错觉" 这也是我很想避免的情况 比如: http://xxx/crud

{
   "User:aa":{
        "username":"test1",
        "password": "123456",
        "state": 1
    },
    "User_address[]": [
        {
        "user_id@": "User:aa/id",
        "addr": "ddd",
        "count": 1
        },
        {
        "user_id@": "User:aa/id",
        "addr": "ddd1",
        "count": 2
        }
    ],
    "@put": "User_address:modifUA",
    "User_address:modifUA": 
    {
        "id": "5e2d528c-106a-4f14-90b2-f27b5943e3e1",
        "user_id@": "User:aa/id",
        "addr": "addr-01",
        "count": 1
    },

    "@explain": true
}

image

未显示声明 method,默认用 GET,至于参数被吞掉,没有实际执行,这是 bug,改掉就好了 哈哈,那我来改掉. 不然我受不了. 用apijson这段时间,我最讨厌的就是json吞并问题

cloudAndMonkey commented 1 year ago

@TommyLemon 我分析了一下代码, 主要有两个点: 1、无法匹配执行流程, 将json语句原样添加到 sqlRequest image 2、子查询出错 "user_id@": "User:aa/id", image 如果 ref 找不到,语句将不会执行, json就会被吞掉 当开启 AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = false; ref就是查询关键词了.

你看这里是 不管IS_UPDATE_MUST_HAVE_ID_CONDITION 的值,无法找到引用对象,就抛异常嘛? image 我想起来了, 我当时为啥要整理 https://github.com/Tencent/APIJSON/issues/467 就是因为ref找不到, json被吞掉,不执行 image

cloudAndMonkey commented 1 year ago

累死我了, json支持事物、多条语句执行, http crud支持 很完善了 我去搞elasticSearch了 后面回过头再来搞 多数据源,以及控制每条语句connection

TommyLemon commented 1 year ago

@TommyLemon 我分析了一下代码, 主要有两个点: 1、无法匹配执行流程, 将json语句原样添加到 sqlRequest image 2、子查询出错 "user_id@": "User:aa/id", image 如果 ref 找不到,语句将不会执行, json就会被吞掉 当开启 AbstractVerifier.IS_UPDATE_MUST_HAVE_ID_CONDITION = false; ref就是查询关键词了.

你看这里是 不管IS_UPDATE_MUST_HAVE_ID_CONDITION 的值,无法找到引用对象,就抛异常嘛? image 我想起来了, 我当时为啥要整理 #467 就是因为ref找不到, json被吞掉,不执行 image

1.GET/GETS/HEAD/HEADS/DELETE 都不会处理 Table[]:[] ,这个没有对应的协议及功能,不用管,用户这么传,原样返回,这是他们用法问题。

2.引用赋值,如果关联的值查不到或者为 null,不能允许继续查询,因为这会导致范围扩大,不符合绝大部分需求,而且有严重的安全隐患,例如 GETS/HEADS/PUT/DELETE 的 id/userId 条件限制因为允许 null 而失效。这不是 bug,是功能特性,所以也不用管。

467 应该是写法问题

https://github.com/Tencent/APIJSON/issues/467#issuecomment-1328735827

TommyLemon commented 1 year ago

累死我了, json支持事物、多条语句执行, http crud支持 很完善了 我去搞elasticSearch了 后面回过头再来搞 多数据源,以及控制每条语句connection

可以的

cloudAndMonkey commented 1 year ago

1.GET/GETS/HEAD/HEADS/DELETE 都不会处理 Table[]:[] ,这个没有对应的协议及功能,不用管,用户这么传,原样返回,这是他们用法问题。

2.引用赋值,如果关联的值查不到或者为 null,不能允许继续查询,因为这会导致范围扩大,不符合绝大部分需求,而且有严重的安全隐患,例如 GETS/HEADS/PUT/DELETE 的 id/userId 条件限制因为允许 null 而失效。这不是 bug,是功能特性,所以也不用管。 @TommyLemon 我知道这是用户使用的问题 吞掉执行语句, crud里面有/POST/PUT/DELETE语句 ,会提交成功的. 要考虑新手入门,练手阶段 吞掉执行语句, explain模式 返回结果要能让人家通过结果知道 为啥没有执行sql语句,是因为引用失败了

cloudAndMonkey commented 1 year ago

我看了apijson elasticSearch demo. 引入 elasticsearch-sql. json里面配置多数据源,我测一下

TommyLemon commented 1 year ago

1.GET/GETS/HEAD/HEADS/DELETE 都不会处理 Table[]:[] ,这个没有对应的协议及功能,不用管,用户这么传,原样返回,这是他们用法问题。

2.引用赋值,如果关联的值查不到或者为 null,不能允许继续查询,因为这会导致范围扩大,不符合绝大部分需求,而且有严重的安全隐患,例如 GETS/HEADS/PUT/DELETE 的 id/userId 条件限制因为允许 null 而失效。这不是 bug,是功能特性,所以也不用管。 @TommyLemon 我知道这是用户使用的问题 吞掉执行语句, crud里面有/POST/PUT/DELETE语句 ,会提交成功的. 要考虑新手入门,练手阶段 吞掉执行语句, explain模式 返回结果要能让人家通过结果知道 为啥没有执行sql语句,是因为引用失败了

这个通过 APIAuto 来解决吧,新增一个提示。类似 "user": {} 这种小写字母开头的,不符合 APIJSON 表名规范,就会有提示。

image

https://apijson.cn/api/?send=false&type=JSON&url=http%3A%2F%2Fapijson.cn%3A8080%2Fget&json={%22user%22:{%22id%22:82001}}

@explain: true 也不返回,这个是 bug,可以在 AbstractObjectParser 中处理下 sqlResponse = null; 加上判断 isExplain 时 sqlResponse = new JSONObject(); put 进 @explain: { "msg": "引用赋值未获取到有效的关联值,返回空" }

https://github.com/Tencent/APIJSON/blob/master/APIJSONORM/src/main/java/apijson/orm/AbstractObjectParser.java#L735-L747

image
cloudAndMonkey commented 1 year ago

@TommyLemon 我看了 官网X-Pack sql(收费)支持: https://www.elastic.co/guide/en/elasticsearch/reference/7.17/sql-getting-started.html 开源: https://github.com/NLPchina/elasticsearch-sql 如果apijson要支持elasticsearch sql,有几个点,需要解决: 1、新增、修改 它们都不支持新增、修改, 如果要支持新增修改, 通过如下语句执行: image elasticsearch-sql 是通过: org.elasticsearch.client.transport.TransportClient 方式执行插入 image image 删除: image apijson需要按照数据源类型, 生成不同格式的新增/修改 sql语句, 删除,查询 还没有细测 2、查询 估计还是会有一部分兼容问题 目前还没有细测,查询是按照jdbc 语句来执行 image

TommyLemon commented 1 year ago

@TommyLemon 我看了 官网X-Pack sql(收费)支持: https://www.elastic.co/guide/en/elasticsearch/reference/7.17/sql-getting-started.html 开源: https://github.com/NLPchina/elasticsearch-sql 如果apijson要支持elasticsearch sql,有几个点,需要解决: 1、新增、修改 它们都不支持新增、修改, 如果要支持新增修改, 通过如下语句执行: image elasticsearch-sql 是通过: org.elasticsearch.client.transport.TransportClient 方式执行插入 image image 删除: image apijson需要按照数据源类型, 生成不同格式的新增/修改 sql语句, 删除,查询 还没有细测 2、查询 估计还是会有一部分兼容问题 目前还没有细测,查询是按照jdbc 语句来执行 image

1、Elasticsearch-SQL 不支持增删改的话,APIJSON 也先不急着支持,用户可以用 RESTful API 的方式自己实现。后续如果这方面需求的用户比较多再考虑。

/refresh 这种接口也让用户自己调用。APIJSON 暂时先主要支持最核心也最常用的查询功能。

2、截屏的代码没有用 APIJSON,可以用 APIJSON 再试试。

TommyLemon commented 1 year ago

之前改 bug 等源码变更,可以先提交 PR 哦,有了 fork 项目,提 PR 只需要 Git 推送到 fork 项目,然后点 Contribute > Open Pull Request,例如

image
cloudAndMonkey commented 1 year ago

@TommyLemon 1、我这两天就提交,应该不用大改了,我明天再回归测试一下 2、用apijson使用elasticSearch 用户可以用 RESTful API 的方式自己实现. 需要我实现接口来新增、修改、删除? 目前apijson除了数据源支持elasticSearch, 执行方法方面如何集成? 比如: 多数据源, 其中一个数据源是 elasticSearch, 执行插入, apijson会生成sql语句,然后调用 执行方法?

cloudAndMonkey commented 1 year ago

@TommyLemon redis这块, 我今天看了一下. redis 也支持 sql语句方式来操作表,比如: https://github.com/RedBeardLab/rediSQL(不更新了), 改为收费版: https://zeesql.com/#pricing https://help.aliyun.com/document_detail/99960.html 我通过docker测试了一下: 支持redis表 新增、修改、删除、查询、分组、关联查询等 image 在某些维度统计,不需要走大数据分析的情况, 能解决elasticSearch无法关联查询的情况

TommyLemon commented 1 year ago

2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。

执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。

这个第三方库倒是支持 SQL 语法比较全,不过 新增和修改 看文档还不支持,可以对比下官方的,看情况决定用哪个。 https://github.com/NLPchina/elasticsearch-sql#sql-features

image
TommyLemon commented 1 year ago

@TommyLemon redis这块, 我今天看了一下. redis 也支持 sql语句方式来操作表,比如: https://github.com/RedBeardLab/rediSQL(不更新了), 改为收费版: https://zeesql.com/#pricing https://help.aliyun.com/document_detail/99960.html 我通过docker测试了一下: 支持redis表 新增、修改、删除、查询、分组、关联查询等 image 在某些维度统计,不需要走大数据分析的情况, 能解决elasticSearch无法关联查询的情况

赞,也可以通过 SQL 语法支持 APIJSON 对接 Redis 了。

cloudAndMonkey commented 1 year ago

2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。

执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。

这个第三方库倒是支持 SQL 语法比较全,不过 新增和修改 看文档还不支持,可以对比下官方的,看情况决定用哪个。 https://github.com/NLPchina/elasticsearch-sql#sql-features image

新增、修改,只是不同的实现而已, 很简单的几行代码就搞定 1、只需要把sql语句转换或者 直接按照不同数据源生成执行语句. 2、 然后调用不同实现的connection、submit等方法 这块代码要动一下手脚, 要扩展维度

TommyLemon commented 1 year ago

是的,只要和 SQL 语法差异不大,往往都容易对接

TommyLemon commented 1 year ago

APIJSON 核心的 ORM 库不依赖具体的 JDBC 驱动哈,保持简洁,只在 SQL/类 SQL 语法上支持生成语句,如果有要必须引入某个数据源的 JDBC 用它们的 class 等特殊要求(例如 ElasticSearchDruidDataSourceFactory),对于 Elasticsearch, Redis 这种广泛使用的数据源可以放到 apijson-framework 集成,其它的通过新增 apijson-column/apijson-router 这样的插件来支持。 非必须的(一般都走标准通用的 JDBC 协议,不强制使用自定义的类),都是用户业务项目中自己依赖。

cloudAndMonkey commented 1 year ago

APIJSON 核心的 ORM 库不依赖具体的 JDBC 驱动哈,保持简洁,只在 SQL/类 SQL 语法上支持生成语句,如果有要必须引入某个数据源的 JDBC 用它们的 class 等特殊要求(例如 ElasticSearchDruidDataSourceFactory),Elasticsearch, Redis 这种广泛使用的数据源可以放到 apijson-framework 集成,其它的通过新增 apijson-column/apijson-router 这样的插件来支持。 非必须的(一般都走标准通用的 JDBC 协议,不强制使用自定义的类),都是用户业务项目中自己依赖。

嗯嗯

cloudAndMonkey commented 1 year ago

@TommyLemon 2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。

执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。

哈哈,我的思路还在深度集成上面, 明白你的意思了, 远程函数里面调用elasticSearch, 我测一下 人家有另外一种选择, 通过SpringContextUtils.getBean(elasticSearchXXX); 方式,直接操作elasticSearch了 如果仅仅是数据源的集成, 功能点上面没有办法和json贴合, 业务功能实现需要用户自己去实现. 并没有给用户减轻工作量呀

cloudAndMonkey commented 1 year ago

是的, 我来把深度集成这块理一下, 哈哈

TommyLemon commented 1 year ago

@TommyLemon 2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。

执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。

哈哈,我的思路还在深度集成上面, 明白你的意思了, 远程函数里面调用elasticSearch, 我测一下 人家有另外一种选择, 通过SpringContextUtils.getBean(elasticSearchXXX); 方式,直接操作elasticSearch了 如果仅仅是数据源的集成, 功能点上面没有办法和json贴合, 业务功能实现需要用户自己去实现. 并没有给用户减轻工作量呀

大部分用户用 Elasticsearch 应该主要是为了海量文本高性能搜索,这个属于查询,所以先接入查询,可以满足这个核心需求。

cloudAndMonkey commented 1 year ago

@TommyLemon 2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。 执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。 哈哈,我的思路还在深度集成上面, 明白你的意思了, 远程函数里面调用elasticSearch, 我测一下 人家有另外一种选择, 通过SpringContextUtils.getBean(elasticSearchXXX); 方式,直接操作elasticSearch了 如果仅仅是数据源的集成, 功能点上面没有办法和json贴合, 业务功能实现需要用户自己去实现. 并没有给用户减轻工作量呀

大部分用户用 Elasticsearch 应该主要是为了海量文本高性能搜索,这个属于查询,所以先接入查询,可以满足这个核心需求。

一步一步来嘛 1、多数据源 2、@Transaction 事物粒度 3、elasticSearch/redis sql操作 4、不兼容部分,看咋处理

cloudAndMonkey commented 1 year ago

@TommyLemon UPDATE user set username = '222' where id = "fbe20363-85ee-4065-b4bb-ae90343a1a0c" and (SELECT count(*) from sys_user_role where user_id = "fbe20363-85ee-4065-b4bb-ae90343a1a0c") > 0 子查询 做为判断条件,和主表字段不挂钩这种情况, 需要支持吗? 除了原生sql, 请问还有其他方式吗?

cloudAndMonkey commented 1 year ago

@TommyLemon

用户业务项目中: DemoSQLExecutor extends APIJSONSQLExecutor image getConnection 应该简化一下, 业务项目不关心connectionMap等信息 这里和业务项目约定好 key获取方式即可.比如通过: datasource 来获取连接 public Connection getConnection(xxxx) throws Exception { if (datasource != null ) { DataSource ds; switch (datasource) { case "HIKARICP": DataSource ds = SpringContextUtils.getBean(DataSource.class); return ds.getConnection(); } } image

cloudAndMonkey commented 1 year ago

@TommyLemon 我梳理了一下 json解析执行完整流程: image 为了支持跨数据源的事务,需要在 AbstractParser 新增一个 // Map<数据源标识, SQLExecutor 实例> Map<String, SQLExecutor> datasourceSQLExecutorMap 1、整个流程只会创建一个 SQLExecutor 2、创建SQLExecutor的时候,还没有创建 createSQLConfig 3、多数据源管理 和connection、rollback、commit、close挂钩 Parser.rollback 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 rollback; Parser.commit 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 commit; Parser.close 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 close; 这种方式简单,先不细化

多数据源实现逻辑,我再想想,还没想清楚 1、子查询、crud中的查询是否新建一个connection和 增/删/改 独立出来 2、默认datasource 3、全局datasource 4、等等

TommyLemon commented 1 year ago

@TommyLemon 2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。 执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。 哈哈,我的思路还在深度集成上面, 明白你的意思了, 远程函数里面调用elasticSearch, 我测一下 人家有另外一种选择, 通过SpringContextUtils.getBean(elasticSearchXXX); 方式,直接操作elasticSearch了 如果仅仅是数据源的集成, 功能点上面没有办法和json贴合, 业务功能实现需要用户自己去实现. 并没有给用户减轻工作量呀

大部分用户用 Elasticsearch 应该主要是为了海量文本高性能搜索,这个属于查询,所以先接入查询,可以满足这个核心需求。

对应一个主流的用法是,先从 Elasticsearch 查出 id 列表,然后再到 MySQL 等关系型数据库中 id IN 查完整数据

image

http://apijson.cn/api/?send=true&type=JSON&url=http%3A%2F%2Fapijson.cn%3A8080%2Fget&json=%7B%0A%20%20%20%20%27Moment-id%5B%5D%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%27Moment%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%27content~%27%3A%20%27a%27%2C%0A%2F%2F%20%20%20%20%20%20%20%20%20%20%27%40database%27%3A%20%27ELASTICSEARCH%27%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%27%5B%5D%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%27Moment%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%27id%7B%7D%40%27%3A%20%27Moment-id%5B%5D%27%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%27%40explain%27%3A%20true%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D

TommyLemon commented 1 year ago

@TommyLemon UPDATE user set username = '222' where id = "fbe20363-85ee-4065-b4bb-ae90343a1a0c" and (SELECT count(*) from sys_user_role where user_id = "fbe20363-85ee-4065-b4bb-ae90343a1a0c") > 0 子查询 做为判断条件,和主表字段不挂钩这种情况, 需要支持吗? 除了原生sql, 请问还有其他方式吗?

用 EXISTS,或 @raw

TommyLemon commented 1 year ago

@TommyLemon

用户业务项目中: DemoSQLExecutor extends APIJSONSQLExecutor image getConnection 应该简化一下, 业务项目不关心connectionMap等信息 这里和业务项目约定好 key获取方式即可.比如通过: datasource 来获取连接 public Connection getConnection(xxxx) throws Exception { if (datasource != null ) { DataSource ds; switch (datasource) { case "HIKARICP": DataSource ds = SpringContextUtils.getBean(DataSource.class); return ds.getConnection(); } } image

APIJSON 现有的所有库都没有依赖具体的 Web 框架,避免局限于只适用于 Spring。 SpringContextUtils 这种某个 Web 框架特有的类不能直接依赖。 这种适配连接池的代码,本来就只要写很少,而且还是初始化时写一次就行,不需要到处写,优化的意义不大。 尤其是确定只用一个连接池库,那就不需要 try catch 了。

cloudAndMonkey commented 1 year ago

@TommyLemon 2、用户直接调用 Elasticsearch 的官方 API(目前是 RESTful API)实现增删改、初始化、权限管理等,也可以用配套的管理界面或 CLI 等。 执行方法是指 SQL 函数?远程函数?还是存储过程?如果是前 2 者应该都没问题,至于存储过程看 Elasticsearch 是否支持。 哈哈,我的思路还在深度集成上面, 明白你的意思了, 远程函数里面调用elasticSearch, 我测一下 人家有另外一种选择, 通过SpringContextUtils.getBean(elasticSearchXXX); 方式,直接操作elasticSearch了 如果仅仅是数据源的集成, 功能点上面没有办法和json贴合, 业务功能实现需要用户自己去实现. 并没有给用户减轻工作量呀

大部分用户用 Elasticsearch 应该主要是为了海量文本高性能搜索,这个属于查询,所以先接入查询,可以满足这个核心需求。

对应一个主流的用法是,先从 Elasticsearch 查出 id 列表,然后再到 MySQL 等关系型数据库中 id IN 查完整数据 image http://apijson.cn/api/?send=true&type=JSON&url=http%3A%2F%2Fapijson.cn%3A8080%2Fget&json=%7B%0A%20%20%20%20%27Moment-id%5B%5D%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%27Moment%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%27content~%27%3A%20%27a%27%2C%0A%2F%2F%20%20%20%20%20%20%20%20%20%20%27%40database%27%3A%20%27ELASTICSEARCH%27%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%2C%0A%20%20%20%20%27%5B%5D%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%27Moment%27%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%27id%7B%7D%40%27%3A%20%27Moment-id%5B%5D%27%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%27%40explain%27%3A%20true%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D

到时候我测一下

cloudAndMonkey commented 1 year ago

@TommyLemon 用户业务项目中: DemoSQLExecutor extends APIJSONSQLExecutor image getConnection 应该简化一下, 业务项目不关心connectionMap等信息 这里和业务项目约定好 key获取方式即可.比如通过: datasource 来获取连接 public Connection getConnection(xxxx) throws Exception { if (datasource != null ) { DataSource ds; switch (datasource) { case "HIKARICP": DataSource ds = SpringContextUtils.getBean(DataSource.class); return ds.getConnection(); } } image

APIJSON 现有的所有库都没有依赖具体的 Web 框架,避免局限于只适用于 Spring。 SpringContextUtils 这种某个 Web 框架特有的类不能直接依赖。 这种适配连接池的代码,本来就只要写很少,而且还是初始化时写一次就行,不需要到处写,优化的意义不大。 尤其是确定只用一个连接池库,那就不需要 try catch 了。 @TommyLemon 哈哈, 可能我表述不当, 我想通过举例说明, connectionMap 可以不用在业务项目 getConnection暴露. 业务项目实现 getConnection, 只关心如何按照约定返回 connection. 为啥会提到这个点, 是因为目前要实现apijson不支持的功能,业务项目@Override某个方法进行修改,随着apijson版本变化,这也是维护成本

TommyLemon commented 1 year ago

这个到可以封装下,例如一个方法 Connection getConnection(String key)

TommyLemon commented 1 year ago

@TommyLemon 我梳理了一下 json解析执行完整流程: image 为了支持跨数据源的事务,需要在 AbstractParser 新增一个 // Map<数据源标识, SQLExecutor 实例> Map<String, SQLExecutor> datasourceSQLExecutorMap 1、整个流程只会创建一个 SQLExecutor 2、创建SQLExecutor的时候,还没有创建 createSQLConfig 3、多数据源管理 和connection、rollback、commit、close挂钩 Parser.rollback 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 rollback; Parser.commit 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 commit; Parser.close 时统一遍历 datasourceSQLExecutorMap 的所有 SQLExecutor 来 close; 这种方式简单,先不细化

多数据源实现逻辑,我再想想,还没想清楚 1、子查询、crud中的查询是否新建一个connection和 增/删/改 独立出来 2、默认datasource 3、全局datasource 4、等等

应该只需要根据数据源分配,如果这样实现有什么问题不好搞,那就再把 method 拼接到 key 中。

cloudAndMonkey commented 1 year ago

@TommyLemon 嗯嗯,这一点我考虑到了,我再想想, 测一下, 再发给你看看, 我哪里没有考虑到的 目前 一个 SQLExecutor, 不需要改造, 合理的. 并且以后支持不同数据源, 也没有影响 如果你有啥想法随时跟我说,谢谢 只是有一点, 一定要轻量 connection, sql语句执行、会滚、提交. 要为以后 支持 redis、elasticSearch 非sql的操作做准备 apijson按照json配置,生成sql或者执行语句(还没想好), 插件或者业务系统自己去执行, apijson就和某个框架隔离开了

TommyLemon commented 1 year ago

好的,多多交流~