APIJSON icon indicating copy to clipboard operation
APIJSON copied to clipboard

一个json(事务)同时支持新增、修改、删除、查询、别名

Open cloudAndMonkey opened this issue 3 years ago • 86 comments

版本5.2.0 1、业务表-插入不同表1:1、1:n、n:n 2、业务表-修改不同表1:1、1:n、n:n 3、业务表-批量删除不同表 实现流程: 1、继承APIJSONParser 2、重载 parseCorrectRequest方法 User__User 通过__分割, tag 和 structure的类名 新增, tag和 structure的类名一样, 更多示例请参见postman image image image 该方法,是参数校验入口 image 特定tag,则走分支流程 image image 修改引用关系 image postman测试示例: 业务表-插入不同表1:1-源码实现

{
    "User__User":{
        "username":"test2",
        "password": "123456",
		"state": 1
    },
    "User_address__User_address": 
	{
	"user_id@": "User/id",
	"addr": "ddd",
	"count": 1
	},
    "tag": "Batch_Tag_UserWithUser_addressList"
}

业务表-插入不同表1:n-源码实现

{
    "User__User":{
        "username":"test1",
        "password": "123456",
		"state": 1
    },
    "User_address[]__User_address[]": [
    	{
    	"user_id@": "User/id",
    	"addr": "ddd",
    	"count": 1
    	},
    	{
    	"user_id@": "User/id",
    	"addr": "ddd1",
    	"count": 2
    	}
    ],
    "tag": "Batch_Tag_UserWithUser_addressList"
}

业务表-插入不同表n:n-源码实现

{
    "User[]__User[]":[
    	{
        "username":"test3",
        "password": "123456",
		"state": 1
    	},
    	{
        "username":"test4",
        "password": "123456",
		"state": 1
    	}
    ],
    "User_address[]__User_address[]": [
    	{
    	"user_id": "94593122-403a-4eb2-a6f0-182ed3da7764",
    	"addr": "ddd",
    	"count": 1
    	},
    	{
    	"user_id": "94593122-403a-4eb2-a6f0-182ed3da7764",
    	"addr": "ddd1",
    	"count": 2
    	}
    ],
    "tag": "Batch_Tag_UserWithUser_addressList"
}

业务表-批量修改不同表1:n-源码实现

{
    "User__User":{
    	"id": "94593122-403a-4eb2-a6f0-182ed3da7764",
        "username":"test1-1",
        "password": "111111",
		"state": 1
    },
    "User_address[]__User_address[]": [
    	{
    	"id": "e8bb9e79-9bbe-49d2-9542-77792368bece",
    	"user_id@": "User/id",
    	"addr": "addr-01",
    	"count": 1
    	},
    	{
    	"id": "4dfee57f-6953-4371-865f-22b6e1957fee",
    	"user_id@": "User/id",
    	"addr": "addr-11",
    	"count": 1
    	}
    ],
    "tag": "Batch_Tag_UserWithUser_addressList"
}

业务表-批量修改不同表n:n-源码实现

{
    "User[]__User[]":[
    	{
    	"id": "f60e829a-1181-4331-ac1e-f5faf64e3a8c",
        "username":"test-3",
        "password": "123456-1",
		"state": 1
    	},
    	{
    	"id": "ca86a2e0-d504-4772-b06a-1a8c9e2b12c9",
        "username":"test-4",
        "password": "123456-1",
		"state": 1
    	}
    ],
    "User_address[]__User_address[]": [
    	{
    	"id": "faf8a605-66a3-4ce1-b774-c499b86a4984",
    	"user_id": "94593122-403a-4eb2-a6f0-182ed3da7764",
    	"addr": "ddd-1",
    	"count": 1
    	},
    	{
    	"id": "ac88ce16-6cdf-41a3-b382-c78452c5a850",
    	"user_id": "94593122-403a-4eb2-a6f0-182ed3da7764",
    	"addr": "ddd-2",
    	"count": 2
    	}
    ],
    "tag": "Batch_Tag_UserWithUser_addressList"
}

业务表-批量删除不同表-源码实现

{
    "User[]__User":{
    	"id{}": ["8e44c04a-6e90-4dfe-b021-3436453c55dd", "94593122-403a-4eb2-a6f0-182ed3da7764","ca86a2e0-d504-4772-b06a-1a8c9e2b12c9"]
    },
    "User_address[]__User_address": {
    	"id{}": ["1ed2dda1-5800-4b69-b128-7771dd79046f", "e8bb9e79-9bbe-49d2-9542-77792368bece","4dfee57f-6953-4371-865f-22b6e1957fee","faf8a605-66a3-4ce1-b774-c499b86a4984"]
    },
    "tag": "Batch_Tag_UserWithUser_addressList"
}

后续我再研究一下 1、支持不同的操作类型,比如 GET、POST、DELETE, 在一个json里面, 才能保证事物 2、function函数 执行语句, 加入事物 框架能支持数组, 把数组拆解为一条一条语句执行, 只要把相关引用 传递进 function应该能搞定,空了研究一下,哈哈

cloudAndMonkey avatar Nov 10 '22 09:11 cloudAndMonkey

赞,感谢分享~

TommyLemon avatar Nov 10 '22 14:11 TommyLemon

把增删改查不同操作放在一个请求 JSON 中,需要额外字段来标记,例如可以是

{
   "Moment": {
     "@method": "POST",
     // TODO 其它字段
   },
   "Comment[]": [
      {
        "@method": "PUT",
        // TODO 其它字段
      }
   ]
}

或者这样更好一些,可以提前知道那些片段属于哪种操作,方便解析,性能也更好:

{
   "@post": "Moment,Comment[]", // 分发到 POST 请求对应的解析处理
   "Moment": {
     // TODO 其它字段
   },
   "Comment[]": [
      {
        // TODO 其它字段
      }
   ],
   "@get": "User", // 分发到 GET 请求对应的解析处理
   "User": {
     // TODO 其它字段
   },
   "Privacy": { // 按 URL 对应的默认方法处理
     // TODO 其它字段
   }
}

对于没有显式声明操作方法的,直接用 URL(/get, /post 等) 对应的默认操作方法

TommyLemon avatar Nov 10 '22 14:11 TommyLemon

@TommyLemon > 临时变量 是以表名为维度 "@post": "Moment,Comment[]", 解决不了同时操作一张表 比如 sys_permission 菜单表 新增一条记录, 要修改父菜单的is_leaf(是否叶子节点:1:是 0:不是)

流程要处理几个地方(还没有细化): 1、校验 2、语句执行 语句执行的地方要能区分一张表不同的 请求操作类型

cloudAndMonkey avatar Nov 11 '22 04:11 cloudAndMonkey

还有一种方法, 通过request structure 字段来支持,通过json格式匹配 1、校验 { "post": [ {"Table_order_list_test": {"MUST":"aa,dd","UPDATE": {"@role": "OWNER,ADMIN","pwdEncrypt-()": "pwdEncrypt(id,password)"}, "REFUSE": "id"}}, {"User[]": {"User[]": [{"MUST":"username,password","REFUSE": "id"}], "UPDATE": {"@role": "OWNER,ADMIN"}}} ] "put": [ {"Table_order_list_test": {"MUST":"aa,dd","UPDATE": {"@role": "OWNER,ADMIN","pwdEncrypt-()": "pwdEncrypt(id,password)"}, "REFUSE": "id"}}, {"User[]": {"User[]": [{"MUST":"username,password","REFUSE": "id"}], "UPDATE": {"@role": "OWNER,ADMIN"}}} ] } 2、语句执行 将 @post、@get 如何打到对象上面跟着语句走

cloudAndMonkey avatar Nov 11 '22 04:11 cloudAndMonkey

目前我能想到比较简单的方式: key: tag-table-post 语句执行 再想办法将 @post、@get 如何打到对象上面跟着语句走

cloudAndMonkey avatar Nov 11 '22 05:11 cloudAndMonkey

@TommyLemon > 临时变量 是以表名为维度 "@post": "Moment,Comment[]", 解决不了同时操作一张表 比如 sys_permission 菜单表 新增一条记录, 要修改父菜单的is_leaf(是否叶子节点:1:是 0:不是)

流程要处理几个地方(还没有细化): 1、校验 2、语句执行 语句执行的地方要能区分一张表不同的 请求操作类型

对同一张表可以用别名来区分不同记录,例如:

{
  "User": {
     //TODO 其它字段
  },
  "User:owner": {
    "@role": "OWNER",
     //TODO 其它字段
  },
  "User:count": {
    "@column": "count(1)",
     //TODO 其它字段
  }
}

具体见 通用文档 > 3.设计规范 > 3.2 功能符 > 新建别名 https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2

TommyLemon avatar Nov 11 '22 11:11 TommyLemon

@TommyLemon > "name:alias",name映射为alias,用alias替代name。可用于 column,Table,SQL函数 等。只用于GET类型、HEAD类型的请求 post请求, 没办法传递 别名呀 { "User:aa":{ "username":"test", "password": "233223", "state": 1 }, "tag": "User" }

{"User:aa":{"username":"test","password":"233223","state":1},"format":true} java.lang.UnsupportedOperationException: POST请求,请在 内传 User:{} !

cloudAndMonkey avatar Nov 11 '22 14:11 cloudAndMonkey

以前没有这样的需求,现在可以新增支持。 ”POST请求,请在 内传 User:{} !“ 这个报错是因为 Request 表 structure 中配置的就是 "User":{} 而不是 "User:aa":{}

TommyLemon avatar Nov 13 '22 11:11 TommyLemon

以前没有这样的需求,现在可以新增支持。 ”POST请求,请在 内传 User:{} !“ 这个报错是因为 Request 表 structure 中配置的就是 "User":{} 而不是 "User:aa":{}

嗯嗯,功能我基本调通了,一些细节我还要调整一下,比如 第一条语句 查询 如果没有结果,将会直接返回 等等

cloudAndMonkey avatar Nov 14 '22 00:11 cloudAndMonkey

以前没有这样的需求,现在可以新增支持。 ”POST请求,请在 内传 User:{} !“ 这个报错是因为 Request 表 structure 中配置的就是 "User":{} 而不是 "User:aa":{} @TommyLemon 单表新增、修改、删除支持别名 #470

cloudAndMonkey avatar Nov 15 '22 08:11 cloudAndMonkey

@TommyLemon 一个json 支持新增(单条、批量)、修改(单条、批量)、删除、查询、别名 实现代码如下: 1、重载 APIJSONParser 实现 parseCorrectRequest 2、注释tag校验 image 3、FormParser 实现单条、批量校验逻辑 `/** * 相同对象,通过别名区分 * @param method * @param tag * @param version * @param name * @param request * @param maxUpdateCount * @param creator * @return * @throws Exception */ private JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception { JSONObject jsonObject = new JSONObject(true); String _tag = null; if (request.keySet() == null || request.keySet().size() == 0) { throw new IllegalArgumentException("json对象格式不正确 !,例如 "User": {}"); } for (String key : request.keySet()) { // key重复直接抛错 if (jsonObject.containsKey(key)) { throw new IllegalArgumentException("json对象名重复,请添加操作类型区分!,例如 method__tag__structureKey, 或者: tag__structureKey"); }

		if(key.startsWith("@") || key.endsWith("@")) {
			jsonObject.put(key, request.get(key));
			continue;
		}
		
		// 处理别名
		if(request.get(key) instanceof JSONObject || request.get(key) instanceof JSONArray) {
			String tmpKey = key;
			if(apijson.JSONObject.isTableArray(key)) {
				tmpKey = (key.substring(0, key.length() - apijson.JSONObject.KEY_ARRAY.length()));
			}
			if(tableAlias.get(tmpKey) == null) {
				int keyIndex = tmpKey.indexOf(":");
				if(keyIndex != -1) {
					tableAlias.put(tmpKey, tmpKey.substring(0, keyIndex));
				}
			}
		}
		
		// 获取执行方法
		if (request.get(key) instanceof JSONObject) {
			String _method = request.getJSONObject(key).getString("@method");
			if(_method != null) {
				method = RequestMethod.valueOf(_method.toUpperCase());
			}
			
			// 判断是否为get请求
			if (RequestMethod.isPublicMethod(method)) {
				jsonObject.put(key, request.getJSONObject(key));
				continue;
			}
			// 非get请求,则进行参数校验
			String tmpTag = request.getJSONObject(key).getString("@tag");
			if(tmpTag != null) {
				_tag = tmpTag;
			}else if(StringUtil.isEmpty(tag)) {
				// 批量操作 tag[] = key[]
				if(apijson.JSONObject.isTableArray(key)) {
					String tmpKey = (key.substring(0, key.length() - apijson.JSONObject.KEY_ARRAY.length()));
					if(tableAlias.get(tmpKey) != null) {
						_tag = tableAlias.get(tmpKey) + apijson.JSONObject.KEY_ARRAY;
					}else {
						// 不存在别名
						_tag = key;
					}
				}else {
					// 单条操作, tag = key
					if(tableAlias.get(key) != null) {
						_tag = tableAlias.get(key);
					}else {
						// 不存在别名
						_tag = key;
					}
				}
			}else {
				// 数组解析成对象,会进入
				if(tableAlias.get(tag) != null) {
					_tag = tableAlias.get(tag);
				}else {
					_tag = tag;
				}
			}
			JSONObject requestItem = new JSONObject();
			requestItem.put(_tag, request.get(key));
			JSONObject object = getLocalStructure(method, _tag, version);
			JSONObject ret = commonVerify(method, _tag, version, name, requestItem, maxUpdateCount, creator, object);
			jsonObject.put(key, ret.getJSONObject(_tag));
		}else if(request.get(key) instanceof JSONArray) {
            jsonObject.put(key, request.getJSONArray(key));
		}else {
			jsonObject.put(key, request.get(key));
		}
	}

	return jsonObject;
}`

4、修改 AbstractParser image image 示例: sql层级最多5层 // 新增、修改、删除 // 执行sql语句条数不能超过5条 { "User:aa":{ "@method": "POST", "username":"test1", "password": "123456", "state": 1 }, "User_address[]": [ { "@method": "POST", "user_id@": "User:aa/id", "addr": "ddd", "count": 1 }, { "@method": "POST", "user_id@": "User:aa/id", "addr": "ddd1", "count": 2 } ], "User_address:modifUA": { "@method": "PUT", "id": "1c051f08-4671-4fef-8ae3-64fc8b45047d", "user_id@": "User:aa/id", "addr": "addr-01", "count": 1 }, "User:delUser":{ "@method": "DELETE", "id{}": ["1d42c09c-0780-4762-8100-a718d7c8a83b", "a1d51e2a-797c-4b3f-afc4-45befcd775ed"] }, "@explain": true } image // 新增、修改、删除、查询 // get请求会导致事物无法提交(看需要是否支持) // get请求最好放到前置函数里面操作,通过前置函数来回填需要新增、修改的参数 { "User:aa":{ "@method": "POST", "username":"test1", "password": "123456", "state": 1 }, "User_address[]": [ { "@method": "POST", "user_id@": "User:aa/id", "addr": "ddd", "count": 1 }, { "@method": "POST", "user_id@": "User:aa/id", "addr": "ddd1", "count": 2 } ], "sql@": { "@method": "GET", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["834df81e-cf8b-40a5-9638-c62fb00e8db4"] } }, "User_address:sUA[]": { "@method": "GET", "User_address": { "user_id{}@": "sql" }, "page": 0, "count": 10, "query": 2 }, "total@": "/User_address:sUA[]/total", "@explain": true } 多条查询: { "sql@": { "@method": "GET", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["64c09bdc-927a-411b-843f-ff3f72b5d5be"] } }, "User_address:ua[]": { "@method": "GET", "User_address": { "user_id{}@": "sql" }, "page": 0, "count": 10, "query": 2 }, "total@": "/User_address:ua[]/total", "sql1@": { "@method": "GET", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["64c09bdc-927a-411b-843f-ff3f72b5d5be"] } }, "User_address:ua1[]": { "@method": "GET", "User_address": { "user_id{}@": "sql1" }, "page": 0, "count": 10, "query": 2 }, "total1@": "/User_address:ua1[]/total", "@explain": true }

cloudAndMonkey avatar Nov 16 '22 08:11 cloudAndMonkey

@TommyLemon 一个json 支持新增(单条、批量)、修改(单条、批量)、删除、查询、别名 实现代码如下: 1、重载 APIJSONParser 实现 parseCorrectRequest 2、注释tag校验 image 3、FormParser 实现单条、批量校验逻辑 /** * 相同对象,通过别名区分 * @param method * @param tag * @param version * @param name * @param request * @param maxUpdateCount * @param creator * @return * @throws Exception */ private JSONObject batchVerify(RequestMethod method, String tag, int version, String name, @NotNull JSONObject request, int maxUpdateCount, SQLCreator creator) throws Exception { JSONObject jsonObject = new JSONObject(true); String _tag = null; if (request.keySet() == null || request.keySet().size() == 0) { throw new IllegalArgumentException("json对象格式不正确 !,例如 "User": {}"); } for (String key : request.keySet()) { // key重复直接抛错 if (jsonObject.containsKey(key)) { throw new IllegalArgumentException("json对象名重复,请添加操作类型区分!,例如 method__tag__structureKey, 或者: tag__structureKey"); }

		if(key.startsWith("@") || key.endsWith("@")) {
			jsonObject.put(key, request.get(key));
			continue;
		}
		
		// 处理别名
		if(request.get(key) instanceof JSONObject || request.get(key) instanceof JSONArray) {
			String tmpKey = key;
			if(apijson.JSONObject.isTableArray(key)) {
				tmpKey = (key.substring(0, key.length() - apijson.JSONObject.KEY_ARRAY.length()));
			}
			if(tableAlias.get(tmpKey) == null) {
				int keyIndex = tmpKey.indexOf(":");
				if(keyIndex != -1) {
					tableAlias.put(tmpKey, tmpKey.substring(0, keyIndex));
				}
			}
		}
		
		// 获取执行方法
		if (request.get(key) instanceof JSONObject) {
			String _method = request.getJSONObject(key).getString("@method");
			if(_method != null) {
				method = RequestMethod.valueOf(_method.toUpperCase());
			}
			
			// 判断是否为get请求
			if (RequestMethod.isPublicMethod(method)) {
				jsonObject.put(key, request.getJSONObject(key));
				continue;
			}
			// 非get请求,则进行参数校验
			String tmpTag = request.getJSONObject(key).getString("@tag");
			if(tmpTag != null) {
				_tag = tmpTag;
			}else if(StringUtil.isEmpty(tag)) {
				// 批量操作 tag[] = key[]
				if(apijson.JSONObject.isTableArray(key)) {
					String tmpKey = (key.substring(0, key.length() - apijson.JSONObject.KEY_ARRAY.length()));
					if(tableAlias.get(tmpKey) != null) {
						_tag = tableAlias.get(tmpKey) + apijson.JSONObject.KEY_ARRAY;
					}else {
						// 不存在别名
						_tag = key;
					}
				}else {
					// 单条操作, tag = key
					if(tableAlias.get(key) != null) {
						_tag = tableAlias.get(key);
					}else {
						// 不存在别名
						_tag = key;
					}
				}
			}else {
				// 数组解析成对象,会进入
				if(tableAlias.get(tag) != null) {
					_tag = tableAlias.get(tag);
				}else {
					_tag = tag;
				}
			}
			JSONObject requestItem = new JSONObject();
			requestItem.put(_tag, request.get(key));
			JSONObject object = getLocalStructure(method, _tag, version);
			JSONObject ret = commonVerify(method, _tag, version, name, requestItem, maxUpdateCount, creator, object);
			jsonObject.put(key, ret.getJSONObject(_tag));
		}else if(request.get(key) instanceof JSONArray) {
            jsonObject.put(key, request.getJSONArray(key));
		}else {
			jsonObject.put(key, request.get(key));
		}
	}

	return jsonObject;
}

4、修改 AbstractParser image image 示例: sql层级最多5层 // 新增、修改、删除 // 执行sql语句条数不能超过5条 { "User:aa":{ "@method": "post", "username":"test1", "password": "123456", "state": 1 }, "User_address[]": [ { "@method": "post", "user_id@": "User:aa/id", "addr": "ddd", "count": 1 }, { "@method": "post", "user_id@": "User:aa/id", "addr": "ddd1", "count": 2 } ], "User_address:modifUA": { "@method": "put", "id": "1c051f08-4671-4fef-8ae3-64fc8b45047d", "user_id@": "User:aa/id", "addr": "addr-01", "count": 1 }, "User:delUser":{ "@method": "delete", "id{}": ["1d42c09c-0780-4762-8100-a718d7c8a83b", "a1d51e2a-797c-4b3f-afc4-45befcd775ed"] }, "@Explain": true } image // 新增、修改、删除、查询 // get请求会导致事物无法提交(看需要是否支持) // get请求最好放到前置函数里面操作,通过前置函数来回填需要新增、修改的参数 { "User:aa":{ "@method": "post", "username":"test1", "password": "123456", "state": 1 }, "User_address[]": [ { "@method": "post", "user_id@": "User:aa/id", "addr": "ddd", "count": 1 }, { "@method": "post", "user_id@": "User:aa/id", "addr": "ddd1", "count": 2 } ], "sql@": { "@method": "get", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["834df81e-cf8b-40a5-9638-c62fb00e8db4"] } }, "User_address:sUA[]": { "@method": "get", "User_address": { "user_id{}@": "sql" }, "page": 0, "count": 10, "query": 2 }, "total@": "/User_address:sUA[]/total", "@Explain": true } 多条查询: { "sql@": { "@method": "get", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["64c09bdc-927a-411b-843f-ff3f72b5d5be"] } }, "User_address:ua[]": { "@method": "get", "User_address": { "user_id{}@": "sql" }, "page": 0, "count": 10, "query": 2 }, "total@": "/User_address:ua[]/total", "sql1@": { "@method": "get", "with": true, "from": "User", "User": { "@column": "id", "id{}": ["64c09bdc-927a-411b-843f-ff3f72b5d5be"] } }, "User_address:ua1[]": { "@method": "get", "User_address": { "user_id{}@": "sql1" }, "page": 0, "count": 10, "query": 2 }, "total1@": "/User_address:ua1[]/total", "@Explain": true }

赞,感谢分享~

TommyLemon avatar Nov 16 '22 15:11 TommyLemon

可以最外层新增传参 "transaction": true 来指定有事务,这个全局关键词目前未支持,需要自己实现下。 然后重写 Parser 中 setAutoCommit begin commit rollback 等事务相关方法。

另外建议 @method 值用全大写,例如 "@method": "GET",保持统一的常量/关键词命名风格,也方便复用 enum RequestMethod,例如 RequestMethod.GET.name().equals(method) 或者 RequestMethod.valueOf(method)

TommyLemon avatar Nov 16 '22 15:11 TommyLemon

可以最外层新增传参 "transaction": true 来指定有事务,这个全局关键词目前未支持,需要自己实现下。 然后重写 Parser 中 setAutoCommit begin commit rollback 等事务相关方法。

另外建议 @method 值用全大写,例如 "@method": "GET",保持统一的常量/关键词命名风格,也方便复用 enum RequestMethod,例如 RequestMethod.GET.name().equals(method) 或者 RequestMethod.valueOf(method)

好的,谢谢

cloudAndMonkey avatar Nov 17 '22 00:11 cloudAndMonkey

可以最外层新增传参 "transaction": true 来指定有事务,这个全局关键词目前未支持,需要自己实现下。 然后重写 Parser 中 setAutoCommit begin commit rollback 等事务相关方法。

另外建议 @method 值用全大写,例如 "@method": "GET",保持统一的常量/关键词命名风格,也方便复用 enum RequestMethod,例如 RequestMethod.GET.name().equals(method) 或者 RequestMethod.valueOf(method)

@TommyLemon json第一次执行,会设置 AbstractSQLExecutor transactionIsolation , GET = 0 , 其他= 4 image

json解析每一条语句执行,只会改变自己的 transactionIsolation image 所以只需要在 AbstractParser onCommit 这里改变判断条件即可: 以前是 get请求直接返回,不执行 commit image 测试示例: 查询、新增

{
    "sql@": {
    	"@method": "GET",
        "with": true,
        "from": "User",
        "User": {
          "@column": "id",
          "id{}": ["c692d9d1-2e23-4055-99fb-66461bda33c3"]
        }
    },
    "User_address:uad[]": {
    	"@method": "GET",
        "User_address": {
            "user_id{}@": "sql"
        },
        "page": 0,
        "count": 10,
        "query": 2
    },
    "total@": "/User_address:uad[]/total",
   "User:aa":{
   		"@method": "POST",
        "username":"test1",
        "password": "123456",
		"state": 1
    },
    "User_address:uad1[]": [
    	{
    	"@method": "POST",
    	"user_id@": "User:aa/id",
    	"addr": "ddd",
    	"count": 1
    	},
    	{
    	"@method": "POST",
    	"user_id@": "User:aa/id",
    	"addr": "ddd1",
    	"count": 2
    	}
    ],
    
    "@explain": true
}

执行结果: 事务生效, 数据入库正常 image

cloudAndMonkey avatar Nov 17 '22 06:11 cloudAndMonkey

你把 WITH(SELECT ...) AS `sql` 也实现了嘛? https://github.com/Tencent/APIJSON/blob/master/Roadmap.md image

TommyLemon avatar Nov 18 '22 07:11 TommyLemon

你把 WITH(SELECT ...) AS sql 也实现了嘛? https://github.com/Tencent/APIJSON/blob/master/Roadmap.md image

好的,我先看看

cloudAndMonkey avatar Nov 21 '22 06:11 cloudAndMonkey

我还要稍微调一下 确认一下, 只有GET 查询 使用 with-as表达式吗? 子查询 删除/修改 采用 in的方式? 还是统一都采用with-as表达式?

@TommyLemon apijson版本: 5.4 mysql8 支持 with as表达式, 提高性能 实现流程图: image

修改源码: AbstractSQLConfig image image 测试用例: // 测试 mysql8 with as表达式 // 用户表 // 用户角色表 // 角色表 // 示例一 单个range ref引用 { "sql@": { "@method": "GET", "with": true, "from": "Sys_role", "Sys_role": { "@column": "id", "role_name": "角色1" } }, "Sys_user_role:sur[]": { "@method": "GET", "Sys_user_role": { "role_id{}@": "sql" } }, "Sys_role_permission:srp[]": { "@method": "GET", "Sys_role_permission": { "role_id{}@": "sql" } }, "@explain": true }
image mysql5.7执行结果: image 场景二 多个range ref引用 { "sql@": { "@method": "GET", "with": true, "from": "Sys_role", "Sys_role": { "@column": "id", "role_name": "角色1" } }, "sql_user@": { "@method": "GET", "with": true, "from": "Sys_user", "Sys_user": { "@column": "id", "id": "f0894db2-6940-4d89-a5b2-4405d0ad0c8f" } }, "Sys_user_role:sur[]": { "@method": "GET", "Sys_user_role": { "role_id{}@": "sql", "user_id{}@": "sql_user" } }, "Sys_role_permission:srp[]": { "@method": "GET", "Sys_role_permission": { "role_id{}@": "sql" } }, "@explain": true }
image mysql5.7执行结果: image 经过相关功能点复测,不影响其他功能点 : 新增、修改、删除、(一个json包含新增、修改、删除) 例如(不想看可以忽略,举一个复杂测试示例): { "sql@": { "@method": "GET", "with": true, "from": "Sys_role", "Sys_role": { "@column": "id", "role_name": "角色1" } }, "sql_user@": { "@method": "GET", "with": true, "from": "Sys_user", "Sys_user": { "@column": "id", "id": "f0894db2-6940-4d89-a5b2-4405d0ad0c8f" } }, "Sys_user_role:sur[]": { "@method": "GET", "Sys_user_role": { "role_id{}@": "sql", "user_id{}@": "sql_user" } }, "Sys_role_permission:srp[]": { "@method": "GET", "Sys_role_permission": { "role_id{}@": "sql" } }, "Sys_user:sy":{ "@method": "POST", "username":"test-4", "password": "123456", "status": 1 }, "Sys_role:sr": { "@method": "POST", "role_name": "角色-4", "role_code": "1111-4", "description": "角色-4" }, "Sys_user_role:sur":{ "@method": "POST", "user_id@": "Sys_user:sy/id", "role_id@": "Sys_role:sr/id" }, "@explain": true }
image image

cloudAndMonkey avatar Nov 22 '22 08:11 cloudAndMonkey

起码 GET 和 GETS 都支持,可以用 RequestMethod.isGetMethod(method, true) 判断; 还可以也支持 HEAD 和 HEADS,可以用 RequestMethod.isPublicMethod(method, true) 判断。

至于 PUT, DELETE 也可以支持,那就是只要 method != RequestMethod.POST 就都支持, 方便实现根据特定子查询条件来修改/删除数据。

TommyLemon avatar Nov 22 '22 12:11 TommyLemon

麻烦提个 PR 贡献代码哦,开源要大家一起参与贡献才会更美好~

image

image

https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%80%E5%AE%9A%E8%A6%81%E8%B4%A1%E7%8C%AE%E4%BB%A3%E7%A0%81

TommyLemon avatar Nov 22 '22 13:11 TommyLemon

起码 GET 和 GETS 都支持,可以用 RequestMethod.isGetMethod(method, true) 判断; 还可以也支持 HEAD 和 HEADS,可以用 RequestMethod.isPublicMethod(method, true) 判断。

至于 PUT, DELETE 也可以支持,那就是只要 method != RequestMethod.POST 就都支持, 方便实现根据特定子查询条件来修改/删除数据。 @TommyLemon 这几种method 我都搞定了 image

我再测一下, 确认没啥问题, 再提PR 测得我两眼冒金花了 这段时间搞下来, 开源、持续维护、功能版本迭代真不容易呀,能坚持下来都是神人, 哈哈😄

目前已经完成的功能点: 1、delete 非id 、ref引用 2、json(事物) 同时支持新增、修改、删除、查询、别名 3、别名 4、with-as支持

cloudAndMonkey avatar Nov 23 '22 09:11 cloudAndMonkey

起码 GET 和 GETS 都支持,可以用 RequestMethod.isGetMethod(method, true) 判断; 还可以也支持 HEAD 和 HEADS,可以用 RequestMethod.isPublicMethod(method, true) 判断。 至于 PUT, DELETE 也可以支持,那就是只要 method != RequestMethod.POST 就都支持, 方便实现根据特定子查询条件来修改/删除数据。 @TommyLemon 这几种method 我都搞定了 image

我再测一下, 确认没啥问题, 再提PR 测得我两眼冒金花了 这段时间搞下来, 开源、持续维护、功能版本迭代真不容易呀,能坚持下来都是神人, 哈哈😄

目前已经完成的功能点: 1、delete 非id 、ref引用 2、json(事物) 同时支持新增、修改、删除、查询、别名 3、别名 4、with-as支持

@cloudAndMonkey 赞,感谢,期待 PR~ 现有功能推荐用 APIAuto 来零代码回归测试,新增功能也可以添加测试 Demo 到 APIAuto https://github.com/TommyLemon/APIAuto

image

还可以额外配置请求参数生成规则 image

image

TommyLemon avatar Nov 23 '22 10:11 TommyLemon

@TommyLemon apijson版本: 5.4 head 子查询,不会经过校验 ,会将 sql@ 解析为 count(xx)执行, 这是一个bug image 目前我是通过 "@method": "GET", 来控制的,你看是否需要调整? { "sql@": { "@method": "GET", "with": true, "from": "Sys_user_role", "Sys_user_role": { "@column": "role_id", "user_id": "4732209c-5785-4827-b532-5092f154fd94" } }, "Sys_role": { "id{}@": "sql" }, "@explain": true }

另外, 我把一个json支持 不同操作,json格式调整了一下, 按照 上次你说的方式 更合理 image

image

cloudAndMonkey avatar Nov 24 '22 08:11 cloudAndMonkey

赞,可以先提 PR,不用一开始就完美。 done is better than perfect. 敏捷开发,小步快跑。只要每次提交都整体比之前更好就行了,通过不断迭代来趋近完美。 而且据我观察 HEAD/HEADS 这两个本来用户就普遍用得很少,可以暂时先不管。

TommyLemon avatar Nov 24 '22 09:11 TommyLemon

@TommyLemon 单条、批量 put、post多条、delete ,"@explain": true 无法返回执行sql语句 image 一个json 包含多条语句 , 能正常返回 image

等我空了看看啥原因

cloudAndMonkey avatar Nov 24 '22 10:11 cloudAndMonkey

建议先提个 PR 把功能提交上去,后面再提 PR 修改 bug,一次提交量太大的话往往不好 code review,bug 风险比较高,也不好定位

TommyLemon avatar Nov 24 '22 11:11 TommyLemon

建议先提个 PR 把功能提交上去,后面再提 PR 修改 bug,一次提交量太大的话往往不好 code review,bug 风险比较高,也不好定位

嗯, 我先记下来

cloudAndMonkey avatar Nov 25 '22 00:11 cloudAndMonkey

批量插入 "@explain": true支持, 数组解析为单条sql语句的时候, 将 全局"@explain": true打入 单条sql语句, 返回结果的时候,再处理一下,应该就可以了 image

cloudAndMonkey avatar Nov 25 '22 00:11 cloudAndMonkey

@TommyLemon batch json (一个json包含增删改查), 应该独立一个 controller方法,新定义一个 method, 自动解析 每个对象/数组/@sql等 不同的method,走不同的流程. 我测下来, 如果url method = delete , json里面包含增删改查, 数组插入并不会执行. url put、post能走完整流程

cloudAndMonkey avatar Nov 25 '22 01:11 cloudAndMonkey

如果一个json支持 不同的method 操作 1、如果配置"@Explain" 能够看到一个事物中的所有执行sql语句 2、前置函数 前置函数能够将json语句, 像数组一样,解析成每一条语句 加入到 事物中

cloudAndMonkey avatar Nov 25 '22 03:11 cloudAndMonkey