From 85ee7b834502d5c6cbf50d485b3e12769b21ab3d Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Wed, 6 Sep 2023 18:22:26 +0800 Subject: [PATCH 01/56] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AF=B9nGQL=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E7=89=87=E6=AE=B5=E5=BC=95=E7=94=A8=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81=EF=BC=8C=E7=B1=BB=E4=BC=BC=E4=BA=8Emybatis=E4=B8=AD?= =?UTF-8?q?=E7=9A=84include=E4=B8=80=E4=B8=AAsql=E7=89=87=E6=AE=B5?= =?UTF-8?q?=E3=80=82=E7=9B=AE=E5=89=8D=E4=BB=85=E6=94=AF=E6=8C=81=E5=90=8C?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E7=9A=84nGQL=E7=89=87=E6=AE=B5=E5=BC=95?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ngbatis/demo/NgbatisDemoApplication.java | 6 ++- .../repository/resource/TestRepository.java | 2 + .../mapper/resource/TestRepository.xml | 12 +++++ .../binding/beetl/functions/IncludeFn.java | 29 +++++++++++ .../ngbatis/io/MapperResourceLoader.java | 51 +++++++++++++------ .../contrib/ngbatis/models/ClassModel.java | 9 ++++ .../contrib/ngbatis/models/NgqlModel.java | 33 ++++++++++++ src/main/resources/beetl.properties | 2 + 8 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java create mode 100644 src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java index e3845549..8984840b 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java @@ -8,6 +8,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.ConfigurableApplicationContext; +import ye.weicheng.ngbatis.demo.repository.resource.TestRepository; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}, scanBasePackages = { "ye.weicheng", "org.nebula.contrib"}) @@ -17,7 +19,9 @@ public class NgbatisDemoApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(NgbatisDemoApplication.class); - app.run(args); + ConfigurableApplicationContext context = app.run(args); + TestRepository testRepository = context.getBean(TestRepository.class); + System.out.println("nGQL引用测试:" + testRepository.includeTest()); } } diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java index d9c6533e..88a82391 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java @@ -19,4 +19,6 @@ public interface TestRepository extends NebulaDaoBasic<Person, String> { Integer testSameClassName(); + + Integer includeTest(); } diff --git a/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml b/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml index d283adc1..111283d2 100644 --- a/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml +++ b/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml @@ -11,5 +11,17 @@ RETURN 1 </select> + <nGQL id="ngql-include-test-value"> + 666 + </nGQL> + + <nGQL id="ngql-include-test"> + RETURN @ng.include('ngql-include-test-value'); + </nGQL> + + <select id="includeTest" resultType="java.lang.Integer"> + @ng.include('ngql-include-test'); + </select> + </mapper> diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java new file mode 100644 index 00000000..ef389606 --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java @@ -0,0 +1,29 @@ +package org.nebula.contrib.ngbatis.binding.beetl.functions; + +import org.beetl.core.Template; +import org.nebula.contrib.ngbatis.models.ClassModel; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.Map; + +/** + * TODO + * 2023-9-6 14:28 lyw. + */ +public class IncludeFn extends AbstractFunction<String,Void,Void,Void,Void,Void>{ + + @Override + public Object call(String ngql) { + Map<String, Object> param = ctx.globalVar; + ClassModel classModel = (ClassModel) param.get("ng_cm"); + if(CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty(classModel.getNgqls().get(ngql))){ + throw new RuntimeException("未找到 nGQL:" + ngql + " 的定义"); + } + String text = classModel.getNgqls().get(ngql).getText(); + Template template = ctx.gt.getTemplate(text); + template.fastBinding(ctx.template.getCtx().globalVar); + template.renderTo(ctx.byteWriter); + return null; + } +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index 927c3439..b8e570d4 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -17,10 +17,7 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -36,6 +33,7 @@ import org.nebula.contrib.ngbatis.exception.ResourceLoadException; import org.nebula.contrib.ngbatis.models.ClassModel; import org.nebula.contrib.ngbatis.models.MethodModel; +import org.nebula.contrib.ngbatis.models.NgqlModel; import org.nebula.contrib.ngbatis.utils.Page; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -117,7 +115,7 @@ public Map<String, ClassModel> parseClassModel(Resource resource) // 获取 子节点 List<Node> nodes = element.childNodes(); // 便历子节点,获取 MethodModel - Map<String, MethodModel> methods = parseMethodModel(cm.getNamespace(), nodes); + Map<String, MethodModel> methods = parseMethodModel(cm, nodes); cm.setMethods(methods); result.put(cm.getNamespace().getName() + PROXY_SUFFIX, cm); } @@ -156,21 +154,34 @@ private void setClassModelBySpaceAnnotation(ClassModel cm) { * @param nodes XXXDao.xml 中 <mapper> 下的子标签。即方法标签。 * @return 返回当前XXXDao类的所有方法信息Map,k: 方法名,v:方法模型(即 xml 里一个方法标签的全部信息) */ - private Map<String, MethodModel> parseMethodModel(Class namespace, List<Node> nodes) + private Map<String, MethodModel> parseMethodModel(ClassModel cm, List<Node> nodes) throws NoSuchMethodException { + Class namespace = cm.getNamespace(); Map<String, MethodModel> methods = new HashMap<>(); List<String> methodNames = getMethodNames(nodes); for (Node methodNode : nodes) { if (methodNode instanceof Element) { - MethodModel methodModel = parseMethodModel(methodNode); - addSpaceToSessionPool(methodModel.getSpace()); - Method method = getNameUniqueMethod(namespace, methodModel.getId()); - methodModel.setMethod(method); - Assert.notNull(method, - "接口 " + namespace.getName() + " 中,未声明 xml 中的出现的方法:" + methodModel.getId()); - checkReturnType(method, namespace); - pageSupport(method, methodModel, methodNames, methods, namespace); - methods.put(methodModel.getId(), methodModel); + + + if(((Element) methodNode).tagName().equalsIgnoreCase("nGQL")){ + if(Objects.isNull(cm.getNgqls())){ + cm.setNgqls(new HashMap<>()); + } + NgqlModel ngqlModel = parseNgqlModel((Element) methodNode); + cm.getNgqls().put(ngqlModel.getId(),ngqlModel); + }else{ + MethodModel methodModel = parseMethodModel(methodNode); + addSpaceToSessionPool(methodModel.getSpace()); + Method method = getNameUniqueMethod(namespace, methodModel.getId()); + methodModel.setMethod(method); + Assert.notNull(method, + "接口 " + namespace.getName() + " 中,未声明 xml 中的出现的方法:" + methodModel.getId()); + checkReturnType(method, namespace); + pageSupport(method, methodModel, methodNames, methods, namespace); + methods.put(methodModel.getId(), methodModel); + } + + } } return methods; @@ -194,6 +205,16 @@ protected MethodModel parseMethodModel(Node node) { return model; } + + /** + * 解析nGQL语句片段 + * @param ngqlEl + * @return + */ + protected NgqlModel parseNgqlModel(Element ngqlEl){ + return new NgqlModel(ngqlEl.id(),ngqlEl.text()); + } + /** * 对暂未支持的 未封箱基础类型 进行检查并给出友好报错 * diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java b/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java index ad063bae..df35e949 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java @@ -22,6 +22,7 @@ public class ClassModel { private String space; private Map<String, MethodModel> methods; + private Map<String,NgqlModel> ngqls; private ResourceLoader resourceLoader; private Resource resource; @@ -87,4 +88,12 @@ public Class getClazz() { public void setClazz(Class clazz) { this.clazz = clazz; } + + public Map<String, NgqlModel> getNgqls() { + return ngqls; + } + + public void setNgqls(Map<String, NgqlModel> ngqls) { + this.ngqls = ngqls; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java new file mode 100644 index 00000000..5e7cf995 --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java @@ -0,0 +1,33 @@ +package org.nebula.contrib.ngbatis.models; + +/** + * TODO + * 2023-9-6 15:45 lyw. + */ +public class NgqlModel { + + private String id; + private String text; + + public NgqlModel(String id, String text) { + this.id = id; + this.text = text; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + +} diff --git a/src/main/resources/beetl.properties b/src/main/resources/beetl.properties index 5942bd02..82c2088a 100644 --- a/src/main/resources/beetl.properties +++ b/src/main/resources/beetl.properties @@ -15,3 +15,5 @@ FN.ng.id =org.nebula.contrib.ngbatis.binding.beetl.functions.IdFn FN.ng.kv =org.nebula.contrib.ngbatis.binding.beetl.functions.KvFn FN.ng.join = org.nebula.contrib.ngbatis.binding.beetl.functions.JoinFn FN.ng.ifStringLike = org.nebula.contrib.ngbatis.binding.beetl.functions.IfStringLike + +FN.ng.include =org.nebula.contrib.ngbatis.binding.beetl.functions.IncludeFn \ No newline at end of file From 2659e2add055268d5c370157155fef72a096a89d Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Thu, 7 Sep 2023 13:28:10 +0800 Subject: [PATCH 02/56] =?UTF-8?q?ng.include=E5=87=BD=E6=95=B0=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=B7=A8mapper=E6=96=87=E4=BB=B6=E5=BC=95=E7=94=A8nGQ?= =?UTF-8?q?L=20=E8=A1=A5=E5=85=85=E4=BA=86=E7=9B=B8=E5=85=B3=E6=96=87?= =?UTF-8?q?=E6=A1=A3=20=E6=B7=BB=E5=8A=A0=E4=BA=86=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BE=8B=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zhCn/md/dev-example/built-in-function.md | 6 +++ docs/zhCn/md/dev-example/custom-crud.md | 41 ++++++++++++++++++- .../ngbatis/demo/NgbatisDemoApplication.java | 6 +-- .../controller/NgqlIncludeController.java | 30 ++++++++++++++ .../repository/NgqlInclude4diffMapperDao.java | 13 ++++++ .../demo/repository/NgqlIncludeDao.java | 13 ++++++ .../repository/resource/TestRepository.java | 4 +- .../mapper/NgqlInclude4diffMapperDao.xml | 12 ++++++ .../main/resources/mapper/NgqlIncludeDao.xml | 20 +++++++++ .../mapper/resource/TestRepository.xml | 12 ------ .../binding/beetl/functions/IncludeFn.java | 24 ++++++++--- 11 files changed, 156 insertions(+), 25 deletions(-) create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java create mode 100644 ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml create mode 100644 ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml diff --git a/docs/zhCn/md/dev-example/built-in-function.md b/docs/zhCn/md/dev-example/built-in-function.md index 41115605..80117c28 100644 --- a/docs/zhCn/md/dev-example/built-in-function.md +++ b/docs/zhCn/md/dev-example/built-in-function.md @@ -139,3 +139,9 @@ public interface PersonDao { 3 | 属性名,用于不将值明文写在 ngql 中,而使用参数名,让 nebula 在参数中取值 | String | N | null +- ng.include + > 引用nGQL片段 + + 参数位 | 参数说明 | 类型 | 必传 | 默认值 + ---|-------------------------------------------------------------------------------------------|--------|---|--- + 1 | 要引用的nGQL片段ID.<br/>引用其他mapper的nGQL片段,片段ID前需要加上片段所在的namespace,例:your.domain.TestDao.nGQL-ID | String | Y \ No newline at end of file diff --git a/docs/zhCn/md/dev-example/custom-crud.md b/docs/zhCn/md/dev-example/custom-crud.md index 87fca652..c186f103 100644 --- a/docs/zhCn/md/dev-example/custom-crud.md +++ b/docs/zhCn/md/dev-example/custom-crud.md @@ -61,4 +61,43 @@ public interface PersonDao { </select> ``` -> Integer result = personDao.select1(); // result : 1 \ No newline at end of file +> Integer result = personDao.select1(); // result : 1 + +## 引用一个nGQL片段 +> 像MyBatis的include标签一样引用一段语句。 + +NgBatis使用内置函数`ng.include`实现引用,`ng.include`的说明可见[Ngbatis内置函数与变量](./built-in-function) +### 定义Dao接口 +```java +package your.domain; + +import org.springframework.data.repository.query.Param; + +public interface TestDao { + + Integer returnMyInt(@Param("myInt") Integer myInt); + +} +``` +### 编写对应的xml文件,并定义nGQL片段和接口方法语句 +```xml + <!-- 如果 space 与 yml 中声明的一致,可不写 --> + <mapper namespace="your.domain.TestDao" space="test"> + + <!-- 在xml文件 mapper 节点下任意位置定义nGQL片段 --> + <nGQL id="my-ngql-id"> + ${myInt} + </nGQL> + + <!-- 定义接口方法语句 --> + <select id="returnMyInt" resultType="java.lang.Integer"> + RETURN @ng.include('my-ngql-id'); + </select> + + </mapper> +``` +nGQL片段自动继承Dao方法所传入的参数,可以在nGQL片段内直接使用,参考上方例子。 + +nGQL片段不限层级,nGQL片段也可以引用nGQL片段,考虑到性能,不建议过多层级的nGQL语句引用。 + +如果需要引用其他mapper内的nGQL片段,使用`ng.include`函数时需要在片段ID前面拼接上片段所在的namespace,如:`@ng.include('your.domain.XxxDao.nGQL-ID');` \ No newline at end of file diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java index 8984840b..e3845549 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplication.java @@ -8,8 +8,6 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.ConfigurableApplicationContext; -import ye.weicheng.ngbatis.demo.repository.resource.TestRepository; @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}, scanBasePackages = { "ye.weicheng", "org.nebula.contrib"}) @@ -19,9 +17,7 @@ public class NgbatisDemoApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(NgbatisDemoApplication.class); - ConfigurableApplicationContext context = app.run(args); - TestRepository testRepository = context.getBean(TestRepository.class); - System.out.println("nGQL引用测试:" + testRepository.includeTest()); + app.run(args); } } diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java new file mode 100644 index 00000000..0a28f6e9 --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java @@ -0,0 +1,30 @@ +package ye.weicheng.ngbatis.demo.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ye.weicheng.ngbatis.demo.repository.NgqlInclude4diffMapperDao; +import ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao; + +/** + * nGQL片段引用测试 + * 2023-9-7 12:40 lyw. + */ +@RestController +@RequestMapping("/include") +public class NgqlIncludeController { + + @Autowired + private NgqlIncludeDao ngqlIncludeDao; + + @Autowired + private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; + + @RequestMapping("/test") + public String test(){ + int a = ngqlIncludeDao.testInclude(1); + int b = ngqlInclude4diffMapperDao.testInclude(2); + return a + "," + b; + } + +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java new file mode 100644 index 00000000..361b04c2 --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java @@ -0,0 +1,13 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.springframework.data.repository.query.Param; + +/** + * nGQL片段跨mapper引用测试 + * 2023-9-7 12:25 lyw. + */ +public interface NgqlInclude4diffMapperDao { + + Integer testInclude(@Param("myInt") Integer myInt); + +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java new file mode 100644 index 00000000..15ea7673 --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java @@ -0,0 +1,13 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.springframework.data.repository.query.Param; + +/** + * nGQL片段引用测试 + * 2023-9-7 12:25 lyw. + */ +public interface NgqlIncludeDao { + + Integer testInclude(@Param("myInt") Integer myInt); + +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java index 88a82391..29ddec40 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java @@ -4,10 +4,11 @@ // // This source code is licensed under Apache 2.0 License. -import javax.annotation.Resource; import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; import ye.weicheng.ngbatis.demo.pojo.Person; +import javax.annotation.Resource; + /** * 数据访问层 样例。 *<p/> @@ -20,5 +21,4 @@ public interface TestRepository extends NebulaDaoBasic<Person, String> { Integer testSameClassName(); - Integer includeTest(); } diff --git a/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml b/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml new file mode 100644 index 00000000..d0b9fb14 --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml @@ -0,0 +1,12 @@ +<!-- + Copyright (c) 2022 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.NgqlInclude4diffMapperDao" space="test"> + + <select id="testInclude" resultType="java.lang.Integer"> + RETURN @ng.include('ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao.include-test-value'); + </select> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml new file mode 100644 index 00000000..c5e0f11e --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml @@ -0,0 +1,20 @@ +<!-- + Copyright (c) 2022 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao" space="test"> + + <select id="testInclude" resultType="java.lang.Integer"> + @ng.include('include-test'); + </select> + + <nGQL id="include-test"> + RETURN @ng.include('include-test-value'); + </nGQL> + + <nGQL id="include-test-value"> + ${myInt} + </nGQL> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml b/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml index 111283d2..d283adc1 100644 --- a/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml +++ b/ngbatis-demo/src/main/resources/mapper/resource/TestRepository.xml @@ -11,17 +11,5 @@ RETURN 1 </select> - <nGQL id="ngql-include-test-value"> - 666 - </nGQL> - - <nGQL id="ngql-include-test"> - RETURN @ng.include('ngql-include-test-value'); - </nGQL> - - <select id="includeTest" resultType="java.lang.Integer"> - @ng.include('ngql-include-test'); - </select> - </mapper> diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java index ef389606..f2bf0235 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java @@ -2,6 +2,7 @@ import org.beetl.core.Template; import org.nebula.contrib.ngbatis.models.ClassModel; +import org.nebula.contrib.ngbatis.models.MapperContext; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -15,12 +16,25 @@ public class IncludeFn extends AbstractFunction<String,Void,Void,Void,Void,Void> @Override public Object call(String ngql) { - Map<String, Object> param = ctx.globalVar; - ClassModel classModel = (ClassModel) param.get("ng_cm"); - if(CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty(classModel.getNgqls().get(ngql))){ - throw new RuntimeException("未找到 nGQL:" + ngql + " 的定义"); + if(StringUtils.isEmpty(ngql)){ + throw new RuntimeException("未指定nGQL片段"); } - String text = classModel.getNgqls().get(ngql).getText(); + int idx = ngql.lastIndexOf("."); + ClassModel classModel; + String ngqlId; + if(idx < 0){ + ngqlId = ngql; + Map<String, Object> param = ctx.globalVar; + classModel = (ClassModel) param.get("ng_cm"); + }else{ + String namespace = ngql.substring(0,idx); + ngqlId = ngql.substring(idx + 1); + classModel = MapperContext.newInstance().getInterfaces().get(namespace + ClassModel.PROXY_SUFFIX); + } + if(CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty(classModel.getNgqls().get(ngqlId))){ + throw new RuntimeException("未找到 nGQL(" + ngql + ") 的定义"); + } + String text = classModel.getNgqls().get(ngqlId).getText(); Template template = ctx.gt.getTemplate(text); template.fastBinding(ctx.template.getCtx().globalVar); template.renderTo(ctx.byteWriter); From d551fe5aa8703945d55c75bf2013e8b46fae9bf0 Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Thu, 7 Sep 2023 14:19:00 +0800 Subject: [PATCH 03/56] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=A3=8E=E6=A0=BC=E7=AC=A6=E5=90=88=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/NgqlIncludeController.java | 24 +++++++++---------- .../repository/NgqlInclude4diffMapperDao.java | 6 ++--- .../demo/repository/NgqlIncludeDao.java | 5 ++-- .../repository/resource/TestRepository.java | 2 +- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java index 0a28f6e9..9077ab4f 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java @@ -10,21 +10,19 @@ * nGQL片段引用测试 * 2023-9-7 12:40 lyw. */ + @RestController @RequestMapping("/include") public class NgqlIncludeController { + @Autowired + private NgqlIncludeDao ngqlIncludeDao; + @Autowired + private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; - @Autowired - private NgqlIncludeDao ngqlIncludeDao; - - @Autowired - private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; - - @RequestMapping("/test") - public String test(){ - int a = ngqlIncludeDao.testInclude(1); - int b = ngqlInclude4diffMapperDao.testInclude(2); - return a + "," + b; - } - + @RequestMapping("/test") + public String test() { + int a = ngqlIncludeDao.testInclude(1); + int b = ngqlInclude4diffMapperDao.testInclude(2); + return a + "," + b; + } } diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java index 361b04c2..461ebb5a 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java @@ -1,13 +1,11 @@ package ye.weicheng.ngbatis.demo.repository; import org.springframework.data.repository.query.Param; - /** * nGQL片段跨mapper引用测试 * 2023-9-7 12:25 lyw. */ -public interface NgqlInclude4diffMapperDao { - - Integer testInclude(@Param("myInt") Integer myInt); +public interface NgqlInclude4diffMapperDao { + Integer testInclude(@Param("myInt") Integer myInt); } diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java index 15ea7673..4f13f80c 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java @@ -6,8 +6,7 @@ * nGQL片段引用测试 * 2023-9-7 12:25 lyw. */ -public interface NgqlIncludeDao { - - Integer testInclude(@Param("myInt") Integer myInt); +public interface NgqlIncludeDao { + Integer testInclude(@Param("myInt") Integer myInt); } diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java index 29ddec40..14d76f10 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java @@ -4,10 +4,10 @@ // // This source code is licensed under Apache 2.0 License. +import javax.annotation.Resource; import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; import ye.weicheng.ngbatis.demo.pojo.Person; -import javax.annotation.Resource; /** * 数据访问层 样例。 From 736e56c5e742a02ddda026998708206072eb1ec8 Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Thu, 7 Sep 2023 14:28:53 +0800 Subject: [PATCH 04/56] =?UTF-8?q?=E5=90=88=E5=B9=B6=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TEST.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 TEST.txt diff --git a/TEST.txt b/TEST.txt new file mode 100644 index 00000000..e69de29b From 20454570796d67137d94bb40ad1b7ee397c2952d Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Thu, 7 Sep 2023 14:39:26 +0800 Subject: [PATCH 05/56] =?UTF-8?q?Revert=20"=E5=90=88=E5=B9=B6=E6=B5=8B?= =?UTF-8?q?=E8=AF=95"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 736e56c5e742a02ddda026998708206072eb1ec8. --- TEST.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 TEST.txt diff --git a/TEST.txt b/TEST.txt deleted file mode 100644 index e69de29b..00000000 From 64f0e72d947c9a9cb4d1010da708ef2900947dad Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Thu, 7 Sep 2023 18:00:32 +0800 Subject: [PATCH 06/56] =?UTF-8?q?ng.include=E5=87=BD=E6=95=B0=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=A2=9D=E5=A4=96=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zhCn/md/dev-example/built-in-function.md | 7 +++-- docs/zhCn/md/dev-example/custom-crud.md | 14 ++++++++- .../controller/NgqlIncludeController.java | 28 ----------------- .../demo/repository/NgqlIncludeDao.java | 3 ++ .../main/resources/mapper/NgqlIncludeDao.xml | 8 +++++ .../demo/repository/NgqlIncludeTest.java | 30 +++++++++++++++++++ .../binding/beetl/functions/IncludeFn.java | 18 +++++++---- 7 files changed, 71 insertions(+), 37 deletions(-) delete mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java create mode 100644 ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java diff --git a/docs/zhCn/md/dev-example/built-in-function.md b/docs/zhCn/md/dev-example/built-in-function.md index 80117c28..1e98fea0 100644 --- a/docs/zhCn/md/dev-example/built-in-function.md +++ b/docs/zhCn/md/dev-example/built-in-function.md @@ -142,6 +142,7 @@ public interface PersonDao { - ng.include > 引用nGQL片段 - 参数位 | 参数说明 | 类型 | 必传 | 默认值 - ---|-------------------------------------------------------------------------------------------|--------|---|--- - 1 | 要引用的nGQL片段ID.<br/>引用其他mapper的nGQL片段,片段ID前需要加上片段所在的namespace,例:your.domain.TestDao.nGQL-ID | String | Y \ No newline at end of file + 参数位 | 参数说明 | 类型 | 必传 | 默认值 + ---|-------------------------------------------------------------------------------------------|---------|---|--- + 1 | 要引用的nGQL片段ID.<br/>引用其他mapper的nGQL片段,片段ID前需要加上片段所在的namespace,例:your.domain.TestDao.nGQL-ID | String | Y + 2 | 引用nGQL片段时额外的参数,在生成语句时优先使用额外参数 | Object | N | null \ No newline at end of file diff --git a/docs/zhCn/md/dev-example/custom-crud.md b/docs/zhCn/md/dev-example/custom-crud.md index c186f103..95725ceb 100644 --- a/docs/zhCn/md/dev-example/custom-crud.md +++ b/docs/zhCn/md/dev-example/custom-crud.md @@ -72,11 +72,14 @@ NgBatis使用内置函数`ng.include`实现引用,`ng.include`的说明可见[ package your.domain; import org.springframework.data.repository.query.Param; +import ye.weicheng.ngbatis.demo.pojo.Person public interface TestDao { Integer returnMyInt(@Param("myInt") Integer myInt); + Integer returnAge(@Param("person") Person person); + } ``` ### 编写对应的xml文件,并定义nGQL片段和接口方法语句 @@ -93,10 +96,19 @@ public interface TestDao { <select id="returnMyInt" resultType="java.lang.Integer"> RETURN @ng.include('my-ngql-id'); </select> + + <!-- nGQL片段额外参数例子 --> + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('my-ngql-id',{'myInt':age}); + </nGQL> </mapper> ``` -nGQL片段自动继承Dao方法所传入的参数,可以在nGQL片段内直接使用,参考上方例子。 +nGQL片段自动继承Dao方法所传入的参数,可以在nGQL片段内直接使用,也可以在`ng.include`函数上指定额外参数,在生成语句时优先使用额外参数,参考上方例子。 nGQL片段不限层级,nGQL片段也可以引用nGQL片段,考虑到性能,不建议过多层级的nGQL语句引用。 diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java deleted file mode 100644 index 9077ab4f..00000000 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/controller/NgqlIncludeController.java +++ /dev/null @@ -1,28 +0,0 @@ -package ye.weicheng.ngbatis.demo.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import ye.weicheng.ngbatis.demo.repository.NgqlInclude4diffMapperDao; -import ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao; - -/** - * nGQL片段引用测试 - * 2023-9-7 12:40 lyw. - */ - -@RestController -@RequestMapping("/include") -public class NgqlIncludeController { - @Autowired - private NgqlIncludeDao ngqlIncludeDao; - @Autowired - private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; - - @RequestMapping("/test") - public String test() { - int a = ngqlIncludeDao.testInclude(1); - int b = ngqlInclude4diffMapperDao.testInclude(2); - return a + "," + b; - } -} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java index 4f13f80c..5e89251a 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java @@ -1,6 +1,7 @@ package ye.weicheng.ngbatis.demo.repository; import org.springframework.data.repository.query.Param; +import ye.weicheng.ngbatis.demo.pojo.Person; /** * nGQL片段引用测试 @@ -9,4 +10,6 @@ public interface NgqlIncludeDao { Integer testInclude(@Param("myInt") Integer myInt); + + Integer returnAge(@Param("person")Person person); } diff --git a/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml index c5e0f11e..0213df7b 100644 --- a/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml +++ b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml @@ -17,4 +17,12 @@ ${myInt} </nGQL> + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('include-test-value',{'myInt':age}); + </nGQL> + </mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java new file mode 100644 index 00000000..dfe8c911 --- /dev/null +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java @@ -0,0 +1,30 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ye.weicheng.ngbatis.demo.pojo.Person; + +/** + * TODO + * 2023-9-7 15:23 lyw. + */ +@SpringBootTest +public class NgqlIncludeTest { + + @Autowired + private NgqlIncludeDao ngqlIncludeDao; + @Autowired + private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; + + @Test + public void test() { + System.out.println("nGQL引用测试:" + ngqlIncludeDao.testInclude(1)); + Person person = new Person(); + person.setAge(18); + System.out.println("nGQL引用额外参数测试:" + ngqlIncludeDao.returnAge(person)); + System.out.println("nGQL跨mapper引用测试:" + ngqlInclude4diffMapperDao.testInclude(1)); + + } + +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java index f2bf0235..7c19158b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java @@ -6,16 +6,17 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.LinkedHashMap; import java.util.Map; /** * TODO * 2023-9-6 14:28 lyw. */ -public class IncludeFn extends AbstractFunction<String,Void,Void,Void,Void,Void>{ +public class IncludeFn extends AbstractFunction<String,Map<String,Object>,Void,Void,Void,Void>{ @Override - public Object call(String ngql) { + public Object call(String ngql,Map<String,Object> args) { if(StringUtils.isEmpty(ngql)){ throw new RuntimeException("未指定nGQL片段"); } @@ -24,8 +25,7 @@ public Object call(String ngql) { String ngqlId; if(idx < 0){ ngqlId = ngql; - Map<String, Object> param = ctx.globalVar; - classModel = (ClassModel) param.get("ng_cm"); + classModel = (ClassModel) ctx.globalVar.get("ng_cm"); }else{ String namespace = ngql.substring(0,idx); ngqlId = ngql.substring(idx + 1); @@ -34,9 +34,17 @@ public Object call(String ngql) { if(CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty(classModel.getNgqls().get(ngqlId))){ throw new RuntimeException("未找到 nGQL(" + ngql + ") 的定义"); } + Map<String,Object> param; + if(!CollectionUtils.isEmpty(args)){ + //防止同名的 子片段参数 覆盖 父片段参数,导致渲染结果与预期不一致。 + param = new LinkedHashMap<>(ctx.globalVar); + param.putAll(args); + }else{ + param = ctx.globalVar; + } String text = classModel.getNgqls().get(ngqlId).getText(); Template template = ctx.gt.getTemplate(text); - template.fastBinding(ctx.template.getCtx().globalVar); + template.fastBinding(param); template.renderTo(ctx.byteWriter); return null; } From 1ae88e9e7e4475b9f5faeace45d120996c8b4d29 Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Sat, 9 Sep 2023 16:27:17 +0800 Subject: [PATCH 07/56] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=80=82=E7=94=A8=E4=BA=8Engbatis-mapper=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E7=9A=84dtd=E7=BA=A6=E6=9D=9F=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E5=BE=97=E5=BC=80=E5=8F=91mapper=E8=83=BD=E6=9C=89=E6=89=80?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/NebulaDaoBasic.xml | 3 +- src/main/resources/ngbatis-mapper.dtd | 41 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/ngbatis-mapper.dtd diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 40bde3a0..0cf144e8 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -3,8 +3,9 @@ This source code is licensed under Apache 2.0 License. --> +<!DOCTYPE mapper SYSTEM "https://nebula-contrib.github.io/ngbatis/ngbatis-mapper.dtd" > <mapper namespace="org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic"> - + <!--region query zoom--> <select id="selectById"> match (n) where id(n) == ${ ng.valueFmt( id ) } return n diff --git a/src/main/resources/ngbatis-mapper.dtd b/src/main/resources/ngbatis-mapper.dtd new file mode 100644 index 00000000..0704415a --- /dev/null +++ b/src/main/resources/ngbatis-mapper.dtd @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!ELEMENT mapper (insert* | update* | delete* | select* | nGQL*)*> +<!ATTLIST mapper +namespace CDATA #IMPLIED +space CDATA +> + +<!ELEMENT insert (#PCDATA)*> +<!ATTLIST insert +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT update (#PCDATA)*> +<!ATTLIST update +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT delete (#PCDATA)*> +<!ATTLIST delete +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT select (#PCDATA)*> +<!ATTLIST select +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +resultType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT nGQL (#PCDATA)*> +<!ATTLIST nGQL +id CDATA #REQUIRED +> \ No newline at end of file From 3a63ac4bcdaacbb90a6e3dabbf05a6c3877dacfb Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 10:38:20 +0800 Subject: [PATCH 08/56] fix: ngbatis doc quick fix the upstream vitepress change breaks the build now stick to a working version first --- .github/workflows/doc_en.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/doc_en.yaml b/.github/workflows/doc_en.yaml index fbb11452..dc8de53b 100644 --- a/.github/workflows/doc_en.yaml +++ b/.github/workflows/doc_en.yaml @@ -34,7 +34,8 @@ jobs: with: repository: graph-cn/ngbatis-docs path: ngbatis-docs - + ref: 7b17bd88148d39643185ba218e3a18ceb3877428 + - name: Place markdown file run: | cp -r docs/en/md/* ngbatis-docs/docs From 5bdde10fff3c6bfc2f4d3737ff50faed168b6080 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 11:15:35 +0800 Subject: [PATCH 09/56] docs: i18n for ng.include - add en docs for ng.include - add gh reaction to ensure change doesn't break docs build - scoped the ci trigger condition for java and doc changes in PR --- .github/workflows/doc_en.yaml | 3 + .../workflows/doc_en_pull_request_dryrun.yaml | 59 +++++++ .github/workflows/pull_request.yml | 6 + docs/en/md/dev-example/built-in-function.md | 166 ++++++++++++++++++ docs/en/md/dev-example/custom-crud.md | 43 ++++- 5 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/doc_en_pull_request_dryrun.yaml create mode 100644 docs/en/md/dev-example/built-in-function.md diff --git a/.github/workflows/doc_en.yaml b/.github/workflows/doc_en.yaml index dc8de53b..7b6b0da9 100644 --- a/.github/workflows/doc_en.yaml +++ b/.github/workflows/doc_en.yaml @@ -5,6 +5,9 @@ on: push: branches: [master] + paths: + - 'docs/**' + - '.github/workflows/**' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: diff --git a/.github/workflows/doc_en_pull_request_dryrun.yaml b/.github/workflows/doc_en_pull_request_dryrun.yaml new file mode 100644 index 00000000..0c2a7ca7 --- /dev/null +++ b/.github/workflows/doc_en_pull_request_dryrun.yaml @@ -0,0 +1,59 @@ +# +name: Dry run Docs Build in PR + +on: + + pull_request: + branches: [master] + paths: + - 'docs/**' + - '.github/workflows/**' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Checkout frontend code + uses: actions/checkout@v3 + with: + repository: graph-cn/ngbatis-docs + path: ngbatis-docs + ref: 7b17bd88148d39643185ba218e3a18ceb3877428 + + - name: Place markdown file + run: | + cp -r docs/en/md/* ngbatis-docs/docs + cp docs/en/vitepress.config.ts ngbatis-docs/docs/.vitepress/config.ts + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + cache-dependency-path: ngbatis-docs/package-lock.json + + - name: Setup Pages + uses: actions/configure-pages@v3 + - name: Build with VitePress + run: | + cd ngbatis-docs + npm ci + npm run docs:build + touch docs/.vitepress/dist/.nojekyll diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 56b92d60..900e0a69 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -10,6 +10,12 @@ on: branches: - master - 'v[0-9]+.*' + paths: + - 'src/**' + - 'ngbatis-demo/**' + - '**/*.xml' + - '*.xml' + - '.github/workflows/**' jobs: build: diff --git a/docs/en/md/dev-example/built-in-function.md b/docs/en/md/dev-example/built-in-function.md new file mode 100644 index 00000000..d0c8a6d4 --- /dev/null +++ b/docs/en/md/dev-example/built-in-function.md @@ -0,0 +1,166 @@ +# Built-in Functions and Variables + +## How to use built-in functions and variables + +```java +package your.domain; + +public interface PersonDao { + void insertPerson( Person person ); +} +``` + +```xml +<mapper namespace="your.domain.PersonDao"> + + <insert id="insertPerson"> + @var kv = ng.kv( ng_args[0], '', true, true ); + @var id = ng.id( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + INSERT VERTEX `${ tagName }` ( + ${ ng.join( @kv.columns, ",", "ng.schemaFmt" ) } + ) + VALUES ${ id } : ( + ${ ng.join( @kv.values ) } + ); + </insert> + +</mapper> +``` + +> In this example, built-in functions such as `ng.kv`, `ng.id`, `ng.tagName`, `ng.join`, `ng.schemaFmt`, and the built-in parameter `ng_args` are used. +> After understanding the usage, we will further introduce the functions in the following content. + + +## Built-in Variables + +- ng_cm ClassModel Dao interface class model, making it easier to get more class information in the xml (1.1.0-rc) +- ng_mm MethodModel Dao interface method model, making it easier to get method information in the xml, including input parameter types. (1.1.0-rc) +- ng_args The original parameters passed to the Dao interface, before serialization. (1.1.0-rc) + +## Built-in Functions + + +- ng.valueFmt + + +> Format data values of uncertain types, ignoring whether to append single quotes and date formatting, and directly pass the original java type + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Value | Object | Y | + 2 | If it is a string, whether to append .* before and after to form a fuzzy query | boolean | N | false + +> Starting from v1.1.2, string types are escaped by default, which can be turned off using: `ValueFmtFn.setEscape( false )` + +- ng.schemaFmt + +> Add **`** before and after the schema name to avoid conflicts with database keywords + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Schema name, such as tagName, edgeName, propertyName | Object | Y + +- ng.tagName + +> Used to get the tag name from the entity class or Dao interface + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object corresponding to the Schema | Object | Y + 2 | Class model, pass in using `ng_cm` | ClassModel | N | null + + + +- ng.pkField + +> Used to get the primary key attribute, java.lang.reflect.Field + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class type | Class<?> | Y + 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | false + +- ng.pkName + +> Used to get the primary key name, String + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Use column name when true, use attribute name when false | Boolean | N | true + +- ng.entityType + +> Used to get the entity class type + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + +- ng.fieldNames + +> Get the attribute name collection (excluding primary key) + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Use column name when true, use attribute name when false | Boolean | N | true + +- ng.id + +> Get the id value + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | true + 3 | If the value is empty, return a new value generated by the primary key generator when true, return null when false | Boolean | N | true + +- ng.kv + +> Get multiple collections through the entity object +> - columns Column name collection +> - valueNames Attribute name collection +> - values Value collection +> - types Attribute types + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Parameter name prefix | String | N | null + 3 | Exclude primary key | Boolean | N | true + 4 | Exclude null values | Boolean | N | true + 5 | If there is no primary key, whether to report an error and interrupt | Boolean | N | true + +- ng.join + +> Format the collection + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Collection to be formatted | Iterable | Y + 2 | Separator between elements | String | N | `,` + 3 | Function name, before each element is concatenated, it can be formatted by the specified formatting function and then concatenated | String | N | null + + +- ng.ifStringLike + +> When the type is a string, prepend and append `.*` + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Value | Object | Y + 2 | Attribute type | Object | N | null + 3 | Attribute name, used to not write the value in plain text in ngql, but use the parameter name to let nebula take the value from the parameters | String | N | null + + +- ng.include + +> Reference nGQL snippet + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | The nGQL snippet ID to be referenced.<br/>To reference nGQL snippets from other mappers, add the namespace of the snippet before the snippet ID, e.g., your.domain.TestDao.nGQL-ID | String | Y + 2 | Additional parameters when referencing nGQL snippets, which will be used preferentially when generating statements | Object | N | null + diff --git a/docs/en/md/dev-example/custom-crud.md b/docs/en/md/dev-example/custom-crud.md index cffd0b5c..bb5b1f27 100644 --- a/docs/en/md/dev-example/custom-crud.md +++ b/docs/en/md/dev-example/custom-crud.md @@ -58,4 +58,45 @@ public interface PersonDao { </select> ``` -> Integer result = personDao.select1(); // result : 1 \ No newline at end of file +> Integer result = personDao.select1(); // result : 1 + + +## Referencing an nGQL Fragment + +> Reference a statement like MyBatis's include tag. + +NgBatis uses the built-in function `ng.include` for referencing. The description of `ng.include` can be found in [Ngbatis Built-in Functions and Variables](./built-in-function). + +### Define Dao Interface + +```xml + <!-- Omit this if the space is consistent with the declaration in the yml file --> + <mapper namespace="your.domain.TestDao" space="test"> + + <!-- Define nGQL fragments anywhere within the mapper node in the XML file --> + <nGQL id="my-ngql-id"> + ${myInt} + </nGQL> + + <!-- Define interface method statement --> + <select id="returnMyInt" resultType="java.lang.Integer"> + RETURN @ng.include('my-ngql-id'); + </select> + + <!-- extra param --> + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('my-ngql-id',{'myInt':age}); + </nGQL> + + </mapper> +``` + +nGQL fragments automatically inherit the parameters passed by the Dao method and can be used directly within the nGQL fragment. You can also specify additional parameters on the `ng.include` function, which will be used with higher priority when generating statements. See the example above. + +nGQL fragments are not limited in hierarchy, and an nGQL fragment can reference another nGQL fragment. However, considering performance, it is not recommended to have too many levels of nGQL statement references. + +If you need to reference an nGQL fragment from another mapper, you need to prepend the namespace of the fragment to the fragment ID when using the `ng.include` function, like this: `@ng.include('your.domain.XxxDao.nGQL-ID');` From 133ba92db224c1156d79151871759b98c7ccbdca Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 12:15:53 +0800 Subject: [PATCH 10/56] ci: add .mk linter and formater - formated existing docs - added ci hook to enforce it, this will be helpful to fix issues before the doc build failed --- .github/workflows/doc_en.yaml | 4 +- .../workflows/doc_en_pull_request_dryrun.yaml | 2 +- .github/workflows/markdown_lint.yaml | 30 + .gitignore | 1 + .markdownlint.json | 8 + CHANGELOG.md | 126 ++-- CONTRIBUTING-CN.md | 21 +- CONTRIBUTING.md | 22 +- EXECUTION-PROCESS.md | 15 +- README-CN.md | 38 +- README.md | 21 +- docs/en/md/dev-example/built-in-function.md | 31 +- docs/en/md/dev-example/custom-crud.md | 21 +- docs/en/md/dev-example/dao-basic.md | 5 +- docs/en/md/dev-example/parameter-for.md | 11 +- docs/en/md/dev-example/parameter-if.md | 27 +- docs/en/md/dev-example/parameter-use.md | 37 +- docs/en/md/dev-example/prepare.md | 9 +- docs/en/md/quick-start/about.md | 8 +- docs/en/md/quick-start/install.md | 22 +- .../advanced-configuration.md | 8 +- .../step-forward-docs/operation-sequence.md | 3 +- docs/zhCn/md/dev-example/built-in-function.md | 35 +- docs/zhCn/md/dev-example/custom-crud.md | 26 +- docs/zhCn/md/dev-example/dao-basic.md | 3 + docs/zhCn/md/dev-example/multi-tag.md | 6 +- docs/zhCn/md/dev-example/parameter-for.md | 8 + docs/zhCn/md/dev-example/parameter-if.md | 27 +- docs/zhCn/md/dev-example/parameter-use.md | 56 +- docs/zhCn/md/dev-example/prepare.md | 10 +- docs/zhCn/md/dev-example/result-built-in.md | 6 +- docs/zhCn/md/dev-example/result.md | 85 ++- docs/zhCn/md/quick-start/about.md | 5 +- docs/zhCn/md/quick-start/features.md | 38 +- docs/zhCn/md/quick-start/install.md | 50 +- .../advanced-configuration.md | 7 +- .../step-forward-docs/operation-sequence.md | 2 + package-lock.json | 706 ++++++++++++++++++ package.json | 20 + 39 files changed, 1357 insertions(+), 203 deletions(-) create mode 100644 .github/workflows/markdown_lint.yaml create mode 100644 .markdownlint.json create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.github/workflows/doc_en.yaml b/.github/workflows/doc_en.yaml index 7b6b0da9..17097261 100644 --- a/.github/workflows/doc_en.yaml +++ b/.github/workflows/doc_en.yaml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - + - name: Checkout frontend code uses: actions/checkout@v3 with: @@ -50,7 +50,7 @@ jobs: node-version: 18 cache: npm cache-dependency-path: ngbatis-docs/package-lock.json - + - name: Setup Pages uses: actions/configure-pages@v3 - name: Build with VitePress diff --git a/.github/workflows/doc_en_pull_request_dryrun.yaml b/.github/workflows/doc_en_pull_request_dryrun.yaml index 0c2a7ca7..e14c955f 100644 --- a/.github/workflows/doc_en_pull_request_dryrun.yaml +++ b/.github/workflows/doc_en_pull_request_dryrun.yaml @@ -29,7 +29,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - + - name: Checkout frontend code uses: actions/checkout@v3 with: diff --git a/.github/workflows/markdown_lint.yaml b/.github/workflows/markdown_lint.yaml new file mode 100644 index 00000000..556fe3b4 --- /dev/null +++ b/.github/workflows/markdown_lint.yaml @@ -0,0 +1,30 @@ +# +name: Lint Markdown + +on: + pull_request: + branches: [master] + paths: + - 'docs/**' + - '*.md' + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + cache-dependency-path: docs/package-lock.json + - name: Install dependencies and lint markdown + run: | + cd docs + npm ci + npm run lint-md diff --git a/.gitignore b/.gitignore index 738fe269..4f2fb8df 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ build/ ### vitepress ### .vitepress +node_modules/ diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..358042de --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "MD013": false, + "MD041": false, + "MD033": false, + "MD024": false, + "MD001": false, +} diff --git a/CHANGELOG.md b/CHANGELOG.md index edb31965..b4800300 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,16 @@ This source code is licensed under Apache 2.0 License. --> # [TODO] + ## Features + - [ ] Expand the function of NebulaDaoBasic - [ ] Add batch interface: - [ ] insertTripletBatch - [ ] insertEdgeBatch - [ ] ... - [ ] Schema support: - - [ ] show metas + - [ ] show metas - [ ] create | alter tag & edge type - [ ] index - [ ] ResultSetUtil more column types support @@ -21,29 +23,35 @@ This source code is licensed under Apache 2.0 License. - [x] Duration ## Dependencies upgrade + - [ ] Springboot 3.x support. # NEXT + ## Dependencies upgrade + - nebula-java: 3.5.0 -> 3.6.0 ## Bugfix + - fix: [#190](https://github.com/nebula-contrib/ngbatis/issues/190) Insert failed when tag has no attributes - chore: removing and exclude some packages: log4j related or useless. - fix: [#194](https://github.com/nebula-contrib/ngbatis/issues/194) we can name the interface by `@Component` and `@Resource`, for example: - `@Component("namedMapper")`: use `@Resource("namedMapper$Proxy")` to inject. (since v1.0) - `@Resource("namedComponent")`: use `@Resource("namedComponent")` to inject. (new feature) -- fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. - > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... +- fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. + > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... > 需要将 `@Param` 移除,或者将 xml 中的参数名改成 注解的参数名,以保证参数名统一 -## Develop behavior change. +## Develop behavior change + - Remove deprecated classes and methods: - org.nebula.contrib.ngbatis.binding.DateDeserializer - org.nebula.contrib.ngbatis.binding.DefaultArgsResolver#customToJson - Dependencies changing: > 如果项目中有用到,且出现相关类找不到的情况,请自行引入 - Exclude: + ```xml <dependency> <groupId>org.springframework.boot</groupId> @@ -66,6 +74,7 @@ This source code is licensed under Apache 2.0 License. ``` - Removing: + ```xml <!-- Why: make it possible to use undertow as web server --> <dependency> @@ -81,10 +90,12 @@ This source code is licensed under Apache 2.0 License. <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> - ``` + ``` # 1.1.5 -## Bugfix + +## 1.1.5 Bugfix + - fix: [#176](https://github.com/nebula-contrib/ngbatis/issues/176) use double quote instead of the original single quote in valuaFmt function - fix: [#181](https://github.com/nebula-contrib/ngbatis/issues/181) when node has multi tag, can not update by subclass - updateById @@ -95,14 +106,18 @@ This source code is licensed under Apache 2.0 License. - fix: [#185](https://github.com/nebula-contrib/ngbatis/issues/185) improve the accuracy of datetime to milliseconds # 1.1.4 -## Develop behavior change. + +## 1.1.4 Behavior Changes + - When a field is declared by java.util.Date, it is no longer allowed to set a value using Timestamp > 当字段由java.util.Date声明时,不再允许使用java.sql.Timestamp设值 -## Bugfix +## 1.1.4 Bugfix + - fix: data error for date type in the database.[#102](https://github.com/nebula-contrib/ngbatis/issues/102) ## Feature + - Clear time type mapping. db type | java type @@ -114,68 +129,86 @@ This source code is licensed under Apache 2.0 License. duration | java.time.Duration # 1.1.3 -## Bugfix + +## 1.1.3 Bugfix + - fix: make the error message clearer when 'use space' failed [#150](https://github.com/nebula-contrib/ngbatis/issues/150) - fix: sessionPool is null when the space name only declared in yml -## Dependencies upgrade + +## 1.1.3 Dependencies upgrade + - nebula-java: 3.4.0 -> 3.5.0 # 1.1.2 -## Develop behavior change. + +## 1.1.2 Behavior Changes + - If an entity type is another entity type's super class, all attribute are being required in database schema except `@Transient` > 如果一个实体类是另一个实体类的父类,则其所有除了注解`@Transient` 了的属性,都需要在数据库中声明。 -## Bugfix -- fix: when vertex has multi tags cannot set value properly.[#120](https://github.com/nebula-contrib/ngbatis/issues/120) +## 1.1.2 Bugfix + +- fix: when vertex has multi tags cannot set value properly.[#120](https://github.com/nebula-contrib/ngbatis/issues/120) - fix: `ng.join` bug [#122](https://github.com/nebula-contrib/ngbatis/issues/122) -## Features + +## 1.1.2 Features + - feat: multi tags support for vertex inserting. - feat: provide default data structure for edge \ vertex \ path \ sub-graph, and their result handler. #103 #118 - feat: NebulaDaoBasic shortest path support. #118 - feat: ng.valueFmt support escape ( default true ). Use `ValueFmtFn.setEscape( false );` to disable this feature. - feat: add config to use `nebula-java` session pool - ``` + + ```yaml nebula: ngbatis: use-session-pool: true - ``` + ``` + +## 1.1.2 Dependencies upgrade -## Dependencies upgrade - nebula-java: 3.3.0 -> 3.4.0 # 1.1.1 + - fixed #89 BigDecimal / Set / Collection serialization to NebulaValue #97 # 1.1.0 -## Features -- springcloud+nacos support #55 -- add upsert tag/edge function #82 + +## 1.1.1 Features + +- springcloud+nacos support #55 +- add upsert tag/edge function #82 - support #39, use @javax.persistence.Transient #43 ## Enhancement -- enhanced: #64 `debug log` print current space in session before switch #79 -- enhanced: NebulaDaoBasic default impls can be overwritten by xml #76 -- optimize #69 display exception detail & enable NebulaDaoBasic to support space switching #70 -- docs typo #52 -## Bugfix -- fixed #89 splitting param serialization into two forms, json and NebulaValue #92 -- fixed #78 use space and gql are executed together incorrect in 3.3.0 #87 -- fixed #73 `selectById` use id value embedding instead of cypher parameter #74 -- fixed #65 `selectByIds` use id values embedding instead of cypher param #67 -- fixed the error of "ng.id" when id is in super class #62 -- fixed #51 The node params support the direct use of the ID value when insert edge #60 -- fixed #56 make it work well when returnType is Map and result is null #58 -- fixed #47 console bug when result type is basic type #48 +- enhanced: #64 `debug log` print current space in session before switch #79 +- enhanced: NebulaDaoBasic default impls can be overwritten by xml #76 +- optimize #69 display exception detail & enable NebulaDaoBasic to support space switching #70 +- docs typo #52 + +## 1.1.1 Bugfix + +- fixed #89 splitting param serialization into two forms, json and NebulaValue #92 +- fixed #78 use space and gql are executed together incorrect in 3.3.0 #87 +- fixed #73 `selectById` use id value embedding instead of cypher parameter #74 +- fixed #65 `selectByIds` use id values embedding instead of cypher param #67 +- fixed the error of "ng.id" when id is in super class #62 +- fixed #51 The node params support the direct use of the ID value when insert edge #60 +- fixed #56 make it work well when returnType is Map and result is null #58 +- fixed #47 console bug when result type is basic type #48 # 1.1.0-rc + 增加了一些内置函数可以在 xml 中使用: + - ng.valueFmt > 对不定类型的数据值进行格式化,忽略是否追加单引号及日期格式化,直接传原始 java类型即可 参数位 | 参数说明 | 类型 | 是否必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y | + 1 | 值 | Object | Y | 2 | 如果是字符串是否在前后追加 .* 形成模糊查询 | boolean | N | false - ng.schemaFmt @@ -190,17 +223,15 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 与Schema对应的实体类对象 | Object | Y + 1 | 与Schema对应的实体类对象 | Object | Y 2 | 类模型,使用 `ng_cm` 传入 | ClassModel | N | null - - - ng.pkField > 用于获取 主键属性,java.lang.reflect.Field 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类类型 | Class<?> | Y + 1 | 实体类类型 | Class<?> | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | false - ng.pkName @@ -208,7 +239,7 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.entityType @@ -217,14 +248,14 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y - ng.fieldNames > 获取属性名集合(不包括主键) 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.id @@ -232,12 +263,13 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | true 3 | 如果值为空,true会通过主键生成器返回新值,false 时 返回空 | Boolean | N | true - ng.kv > 通过实体对象或者获取多个集合 + > > - columns 列名集合 > - valueNames 属性名集合 > - values 值集合 @@ -245,7 +277,7 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 参数名前缀 | String | N | null 3 | 是否排除主键 | Boolean | N | true 4 | 是否排除空值 | Boolean | N | true @@ -256,19 +288,17 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 待格式化的集合 | Iterable | Y - 2 | 元素间的分隔符 | String | N | `,` + 1 | 待格式化的集合 | Iterable | Y + 2 | 元素间的分隔符 | String | N | `,` 3 | 函数名,各元素拼接前,可进行函数名指定的格式化函数先行格式化,再拼接 | String | N | null - - ng.ifStringLike > 类型为字符串时,前后拼接 `.*` 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y + 1 | 值 | Object | Y 2 | 属性类型 | Object | N | null 3 | 属性名,用于不将值明文写在 ngql 中,而使用参数名,让 nebula 在参数中取值 | String | N | null - # 1.1.0-beta diff --git a/CONTRIBUTING-CN.md b/CONTRIBUTING-CN.md index f8c12ce4..fb4148b0 100644 --- a/CONTRIBUTING-CN.md +++ b/CONTRIBUTING-CN.md @@ -1,21 +1,40 @@ # 如何贡献代码? +## Markdown 格式检查 + +提交带有 `.md` 后缀的文件前,可以先进行格式检查。 + +```bash +npm ci +npm run lint-md +``` + +如遇到任何格式错误,请在提交前修复。大多数情况下,内置的格式化工具可能会有所帮助。 + +```bash +npm run format-md +``` + ## 环境要求 + - JDK >= 8 - NebulaGraph > v3.0 - Springboot 2.x - Maven ## 克隆仓库 + 1. 在仓库主页右上角fork到自己的仓库 2. 从自己的仓库中clone到本地 ## 开发步骤 + 1. 如果是第一次贡献,请在 pom.xml 添加作者信息 2. 按你的想法开发功能,把好功能固化下来与其他开发者分享 3. 在 `CHANGELOG.md` 中描述新增的功能及使用方式、场景 ## 运行测试用例及代码风格检查 + 1. 在`ngbatis-demo/test`中运行单元测试 2. 使用maven插件做代码风格检查:`maven->plugins->checkstyle->checkstyle:check` @@ -23,4 +42,4 @@ ## 体会分享所带来的快乐 -> 有任何问题,请放心提issue \ No newline at end of file +> 有任何问题,请放心提issue diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9a4e9fb8..ccf860dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,42 @@ # How To Contribute +## Markdown Lint + +We could lint markdown files before commiting. + +```bash +npm ci +npm run lint-md +``` + +In case of any linting errors, please fix them before commiting. The buildin formatter may help in most cases. + +```bash +npm run format-md +``` + ## Version base + You should be having: + - JDK >= 8 - NebulaGraph > v3.0 - Springboot 2.x - Maven ## Clone the repository + 1. Click the `fork` button on the top right of this page. 2. Download the project to your machine. ## Start develop + 1. Add developer in pom.xml if you are the first time to contributing. 2. Use your ideas to make ngbatis better. 3. Describe changes in `CHANGELOG.md` ## Make sure everything goes well + 1. Run unit tests in `ngbatis-demo/test` 2. Use maven plugins to check code style: `maven->plugins->checkstyle->checkstyle:check` @@ -24,4 +44,4 @@ You should be having: ## Experience the joy brought by sharing -> If you have any questions, issue please. \ No newline at end of file +> If you have any questions, issue please. diff --git a/EXECUTION-PROCESS.md b/EXECUTION-PROCESS.md index 33a64e26..fa52131a 100644 --- a/EXECUTION-PROCESS.md +++ b/EXECUTION-PROCESS.md @@ -6,7 +6,9 @@ This source code is licensed under Apache 2.0 License. --> # 框架执行过程详述 + ## 初始化 + 1. 交由Springboot启动扫描,入口声明配置为:[spring.factories](./src/main/resources/META-INF/spring.factories) , 2. 启动类为:[NgbatisContextInitialize](src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java) 3. 初始化过程 @@ -35,9 +37,11 @@ This source code is licensed under Apache 2.0 License. > 至此完成 ngbatis 动态代理的初始化过程 ## 应用配置,主类 [Env](src/main/java/org/nebula/contrib/ngbatis/Env.java) + 1. 声明nGQL参数解析器,默认方案使用 beetl 模板引擎进行解析。[BeetlTextRender](./src/main/java/org/nebula/contrib/ngbatis/binding/BeetlTextRender.java) > 替换方式为:自行实现 [TextResolver](src/main/java/org/nebula/contrib/ngbatis/TextResolver.java)并以 @Primary 的方式交由spring管理 2. 指定主键生成器(vertex id 与 edge rank 值设置器),可使用时间戳主键生成来获取主键,但建议按自身应用的架构自行实现主键生成。 + ```java @Configuration public class PkGeneratorConfig { @@ -47,10 +51,11 @@ This source code is licensed under Apache 2.0 License. } } ``` -3. 可通过继承[AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java)进行更多类型结果的实体化 +3. 可通过继承[AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java)进行更多类型结果的实体化 ## 运行时 + 1. 业务方通过反转注入的方式,将动态代理类注入到业务类中。 2. 业务类调用实际方法,并传入参数 3. 动态代理执行 MapperProxy.invoke( 接口名, 方法名, 参数列表 ) @@ -60,13 +65,9 @@ This source code is licensed under Apache 2.0 License. 4. 结果集处理,结果集处理器路由[ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver.java),默认为 [DefaultResultResolver](./src/main/java/org/nebula/contrib/ngbatis/binding/DefaultResultResolver.java),由方法模型中接口声明的返回值与额外声明的泛型resultType共同决定采用何种[ResultHandler](src/main/java/org/nebula/contrib/ngbatis/ResultHandler.java)对结果进行处理。**在这个小步骤中,完成 ORM 过程。** ## 开发者使用思路(如无特殊需求,复杂拓展请见【应用配置】) + 1. 指定主键生成器,参考【应用配置.2】 -2. 创建 XXXDao.java +2. 创建 XXXDao.java 3. 创建 XXXDao.xml 并指定 namespace 为 XXXDao.java 4. 在 XXXDao.xml 中编写 nGQL 5. 业务调用时直接注入 XXXDao,调用对应方法即可获取并执行对应 nGQL,无需处理结果集,便能拿到所需 实体对象 - - - - - diff --git a/README-CN.md b/README-CN.md index 7d6776e9..a2118ae9 100644 --- a/README-CN.md +++ b/README-CN.md @@ -24,13 +24,17 @@ This source code is licensed under Apache 2.0 License. 请看设计文档 [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) ## 项目要求 + - Springboot - Maven - Java 8+ ## 如何使用(可在克隆代码后,参考 ngbatis-demo 项目) + ### 在项目引入 - - Maven + +- Maven + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -38,15 +42,19 @@ This source code is licensed under Apache 2.0 License. <version>1.1.5</version> </dependency> ``` - - Gradle + +- Gradle + ```groovy implementation 'org.nebula-contrib:ngbatis:1.1.5' ``` -### 参考 [【ngbatis-demo】](./ngbatis-demo),与springboot无缝集成。在该项目的 test 中还有api的样例。在开发过程中每增加一个特性也都会同步更新ngbatis-demo的用例。 +### 参考 [【ngbatis-demo】](./ngbatis-demo),与springboot无缝集成。在该项目的 test 中还有api的样例。在开发过程中每增加一个特性也都会同步更新ngbatis-demo的用例 ### 配置数据库 + 在 application.yml 中添加配置 **将数据源修改成可访问到的NebulaGraph** + ```yml nebula: ngbatis: @@ -69,7 +77,9 @@ nebula: min-cluster-health-rate: 1.0 enable-ssl: false ``` + ### 扫描动态代理的 bean + ```java @SpringBootApplication(scanBasePackages = { "org.nebula", "your.domain"}) public class YourApplication { @@ -78,12 +88,16 @@ public class YourApplication { } } ``` + > 如果项目中使用的是 SpringCloud, -> 请使用`@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` +> 请使用`@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` ## 日常开发示例 + ### 自己编写 nGQL (MyBatis的思路) + #### 声明数据访问接口 + ```java package ye.weicheng.ngbatis.demo.repository; @@ -102,8 +116,11 @@ public interface TestRepository { } ``` + #### 编写数据访问语句 + resource/mapper/TestRepository.xml + ```xml <mapper namespace= @@ -155,6 +172,7 @@ resource/mapper/TestRepository.xml ### 使用基类自带的 nGQL 实现图的基本操作(MyBatis-plus)的思路 #### model-vertex + ```java package com.example.model.vertex.Person; @@ -170,7 +188,9 @@ public class Person { private Integer age; } ``` + #### model-edge + ```java package com.example.model.edge.Like; @@ -189,6 +209,7 @@ public class Like { ``` #### dao + ```java package com.example.dao; @@ -197,7 +218,9 @@ import com.example.model.vertex.Person; public interface PersonDao extends NebulaDaoBasic<Person, String>{} ``` + #### xml(不可缺少) + ```xml <mapper namespace= @@ -205,7 +228,9 @@ public interface PersonDao extends NebulaDaoBasic<Person, String>{} > </mapper> ``` + #### service + ```java package com.example.service; @@ -267,8 +292,9 @@ public class PersonServiceImpl { ``` ## 特别声明的上游项目 -- [beetl](https://gitee.com/xiandafu/beetl), BSD-3, Beetl模板引擎是项目很重要的组成部分(as is). +- [beetl](https://gitee.com/xiandafu/beetl), BSD-3, Beetl模板引擎是项目很重要的组成部分(as is). ## 开源协议 -项目遵循 [Apache License, Version 2.0, January 2004](https://www.apache.org/licenses/LICENSE-2.0) 开源协议。 \ No newline at end of file + +项目遵循 [Apache License, Version 2.0, January 2004](https://www.apache.org/licenses/LICENSE-2.0) 开源协议。 diff --git a/README.md b/README.md index ac9148fc..5908293a 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ If you prefer JPA, [graph-ocean](https://github.com/nebula-contrib/graph-ocean) See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) ## Requirements + - Springboot - Maven - Java 8+ @@ -35,6 +36,7 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) - Include in your `pom.xml` - Maven + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -42,7 +44,9 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) <version>1.1.5</version> </dependency> ``` + - Gradle + ```groovy implementation 'org.nebula-contrib:ngbatis:1.1.5' ``` @@ -75,6 +79,7 @@ nebula: min-cluster-health-rate: 1.0 enable-ssl: false ``` + - Dynamically register beans ```java @@ -85,12 +90,16 @@ public class YourApplication { } } ``` -> If SpringCloud is used in your project, + +> If SpringCloud is used in your project, > please use `@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` instead. ## Examples + ### a. The MyBatis fashion(compose nGQL queries) + #### a.1 Declare the data access interface + ```java package ye.weicheng.ngbatis.demo.repository; @@ -109,7 +118,9 @@ public interface TestRepository { } ``` + #### a.2 The query statments + `resource/mapper/TestRepository.xml` ```xml @@ -163,6 +174,7 @@ public interface TestRepository { ### b. The MyBatis-plus fashion #### b.1 model-vertex + ```java package com.example.model.vertex.Person; @@ -178,7 +190,9 @@ public class Person { private Integer age; } ``` + #### b.2 model-edge + ```java package com.example.model.edge.Like; @@ -197,6 +211,7 @@ public class Like { ``` #### b.3 dao + ```java package com.example.dao; @@ -205,6 +220,7 @@ import com.example.model.vertex.Person; public interface PersonDao extends NebulaDaoBasic<Person, String>{} ``` + #### b.4 xml > Note, this is a mandatory requirement. @@ -216,7 +232,9 @@ public interface PersonDao extends NebulaDaoBasic<Person, String>{} > </mapper> ``` + #### b.5 service + ```java package com.example.service; @@ -281,7 +299,6 @@ public class PersonServiceImpl { - [beetl](https://gitee.com/xiandafu/beetl), BSD-3, we proudly use the beetl template language as our template engine, which is consumed in binary package(as is). - ## License NGBATIS is under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/docs/en/md/dev-example/built-in-function.md b/docs/en/md/dev-example/built-in-function.md index d0c8a6d4..8bff9c1c 100644 --- a/docs/en/md/dev-example/built-in-function.md +++ b/docs/en/md/dev-example/built-in-function.md @@ -31,7 +31,6 @@ public interface PersonDao { > In this example, built-in functions such as `ng.kv`, `ng.id`, `ng.tagName`, `ng.join`, `ng.schemaFmt`, and the built-in parameter `ng_args` are used. > After understanding the usage, we will further introduce the functions in the following content. - ## Built-in Variables - ng_cm ClassModel Dao interface class model, making it easier to get more class information in the xml (1.1.0-rc) @@ -40,15 +39,13 @@ public interface PersonDao { ## Built-in Functions - - ng.valueFmt - > Format data values of uncertain types, ignoring whether to append single quotes and date formatting, and directly pass the original java type Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Value | Object | Y | + 1 | Value | Object | Y | 2 | If it is a string, whether to append .* before and after to form a fuzzy query | boolean | N | false > Starting from v1.1.2, string types are escaped by default, which can be turned off using: `ValueFmtFn.setEscape( false )` @@ -67,18 +64,16 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object corresponding to the Schema | Object | Y + 1 | Entity class object corresponding to the Schema | Object | Y 2 | Class model, pass in using `ng_cm` | ClassModel | N | null - - - ng.pkField > Used to get the primary key attribute, java.lang.reflect.Field Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class type | Class<?> | Y + 1 | Entity class type | Class<?> | Y 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | false - ng.pkName @@ -87,7 +82,7 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object | Object | Y + 1 | Entity class object | Object | Y 2 | Use column name when true, use attribute name when false | Boolean | N | true - ng.entityType @@ -96,7 +91,7 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object | Object | Y + 1 | Entity class object | Object | Y - ng.fieldNames @@ -104,7 +99,7 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object | Object | Y + 1 | Entity class object | Object | Y 2 | Use column name when true, use attribute name when false | Boolean | N | true - ng.id @@ -113,13 +108,14 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object | Object | Y + 1 | Entity class object | Object | Y 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | true 3 | If the value is empty, return a new value generated by the primary key generator when true, return null when false | Boolean | N | true - ng.kv > Get multiple collections through the entity object +> > - columns Column name collection > - valueNames Attribute name collection > - values Value collection @@ -127,7 +123,7 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Entity class object | Object | Y + 1 | Entity class object | Object | Y 2 | Parameter name prefix | String | N | null 3 | Exclude primary key | Boolean | N | true 4 | Exclude null values | Boolean | N | true @@ -139,22 +135,20 @@ public interface PersonDao { Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Collection to be formatted | Iterable | Y - 2 | Separator between elements | String | N | `,` + 1 | Collection to be formatted | Iterable | Y + 2 | Separator between elements | String | N | `,` 3 | Function name, before each element is concatenated, it can be formatted by the specified formatting function and then concatenated | String | N | null - - ng.ifStringLike > When the type is a string, prepend and append `.*` Parameter Position | Parameter Description | Type | Required | Default Value ---|---|---|---|--- - 1 | Value | Object | Y + 1 | Value | Object | Y 2 | Attribute type | Object | N | null 3 | Attribute name, used to not write the value in plain text in ngql, but use the parameter name to let nebula take the value from the parameters | String | N | null - - ng.include > Reference nGQL snippet @@ -163,4 +157,3 @@ public interface PersonDao { ---|---|---|---|--- 1 | The nGQL snippet ID to be referenced.<br/>To reference nGQL snippets from other mappers, add the namespace of the snippet before the snippet ID, e.g., your.domain.TestDao.nGQL-ID | String | Y 2 | Additional parameters when referencing nGQL snippets, which will be used preferentially when generating statements | Object | N | null - diff --git a/docs/en/md/dev-example/custom-crud.md b/docs/en/md/dev-example/custom-crud.md index bb5b1f27..e598719a 100644 --- a/docs/en/md/dev-example/custom-crud.md +++ b/docs/en/md/dev-example/custom-crud.md @@ -2,8 +2,10 @@ - > When using this method, the familiarity with nGQL and cypher will be higher. Developers who are not familiar with it can learn about it through【[What Is nGQL](https://docs.nebula-graph.io/3.6.0/3.ngql-guide/1.nGQL-overview/1.overview/)】. - > In addition, the template engine used here is Beetl. + > > - [Beetl Docs-Delimiters And Placeholder Symbols](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947), mainly look at placeholders. Ngbatis has made variable settings. If it is only parameter filling, you can ignore the use of delimiters. 【See [[Param Usage](./parameter-use)] for details】 However, parameter condition control and parameter loop delimiter are almost inevitable. Due to the difference in configuration of `Beetl` in `ngbatis`, if the delimiter is involved in the document, the `<% %>` will be replaced by `@ \n`, for example: +> > ```diff > - <%if ( aBool ) { > - @@ -12,16 +14,18 @@ > + > + @} > ``` - > - [Beetl Docs-Functions Used to Process Parameters](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) +> + > - [Beetl Docs-Functions Used to Process Parameters](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) > - [Beetl Docs-Condition Control Statements](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)【See [Param Condition Control](./parameter-if) for details】 > - [Beetl Docs-Loop Statements](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)【See [Param Loop](./parameter-for) for details】 > - [Beetl-Online test widget](http://ibeetl.com/beetlonline/) - The same as [By Basic DAO](./dao-basic), We need to create a XXXDao.java file and XXXDao.xml file. ## Creating file in Dao layer -### Create a Dao corresponding to Person. If you do not need to use the basic class method, it is unnecessary to inherit NebulaDaoBasic. + +### Create a Dao corresponding to Person. If you do not need to use the basic class method, it is unnecessary to inherit NebulaDaoBasic + ```java package your.domain; @@ -33,25 +37,31 @@ public interface PersonDao { ``` ### Create a file named PersonDao.xml file. The default location is: `/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> </mapper> ``` + > XXXDao.java does not need to be annotated by `@Mapper` or `@Component`, it will be discovered by namespace and automatically registered as a bean. > The premise is that the namespace needs to be in the scanBasePackages value under the @SpringBootApplication annotation. > For example: @SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) -## How to let Java programs execute ` nGQL | cypher` through ngbatis +## How to let Java programs execute `nGQL | cypher` through ngbatis + +### Take a simple query statement as an example -### Take a simple query statement as an example: #### Adding interface in PersonDao.java + ```java Integer select1(); ``` + > In the current version, the return value type and method parameter type of the interface. If it is a basic type, only the wrapper class is supported. For example, please write int as Integer. #### Adding a tag in PersonDao.xml + ```xml <select id="select1"> RETURN 1 @@ -60,7 +70,6 @@ public interface PersonDao { > Integer result = personDao.select1(); // result : 1 - ## Referencing an nGQL Fragment > Reference a statement like MyBatis's include tag. diff --git a/docs/en/md/dev-example/dao-basic.md b/docs/en/md/dev-example/dao-basic.md index eddc02ae..3e35d6fc 100644 --- a/docs/en/md/dev-example/dao-basic.md +++ b/docs/en/md/dev-example/dao-basic.md @@ -1,6 +1,7 @@ # By Basic DAO ## Create a Dao corresponding to `Person` and extends NebulaDaoBasic + ```java package your.domain; @@ -12,6 +13,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## Create a file named `PersonDao.xml`. The default location is `/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -19,6 +21,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## Examples in the service layer + ```java @Service @@ -92,4 +95,4 @@ public class PersonServiceImpl { } -``` \ No newline at end of file +``` diff --git a/docs/en/md/dev-example/parameter-for.md b/docs/en/md/dev-example/parameter-for.md index 908fccd0..802a457d 100644 --- a/docs/en/md/dev-example/parameter-for.md +++ b/docs/en/md/dev-example/parameter-for.md @@ -2,6 +2,7 @@ > There is a big difference between ngbatis and mybatis in the loop part, and the loop syntax of Beetl is used. Please refer to official documents for details.【[1.10 Loop statement](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)】 > Due to the difference in configuration of `Beetl` in `ngbatis`, the `<% %>` will be replaced by `@ \n`, for example: + ```diff - <%for ( item in list ) { - @@ -12,7 +13,9 @@ ``` ## Looping in Map , which can be used for dynamic query + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // person: { "name": "Diana", "gender": "F" } @@ -20,6 +23,7 @@ ``` - PersonDao.xml + ```xml <select id="selectByPerson"> MATCH (n: person) @@ -35,7 +39,9 @@ ``` ## Looping in List , which can be used for batch processing + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // personList: [{"gender":"F","name":"Diana"},{"gender":"M","name":"Tom"},{"gender":"F","name":"Jerry"}] @@ -43,11 +49,13 @@ ``` - The parameter is : + ```json :param personList => [{"gender":"F","name":"Diana"},{"gender":"M","name":"Tom"},{"gender":"F","name":"Jerry"}] ``` - PersonDao.xml + ```xml <insert id="insertPersonList"> @for ( p in personList ) { @@ -56,7 +64,8 @@ </insert> ``` -- The statements to be executed are: +- The statements to be executed are: + ```sql INSERT VERTEX `person` ( name, gender ) VALUES 'Diana' : ( 'Diana', 'F' ); INSERT VERTEX `person` ( name, gender ) VALUES 'Tom' : ( 'Tom', 'M' ); diff --git a/docs/en/md/dev-example/parameter-if.md b/docs/en/md/dev-example/parameter-if.md index 5525ba77..af41348f 100644 --- a/docs/en/md/dev-example/parameter-if.md +++ b/docs/en/md/dev-example/parameter-if.md @@ -2,6 +2,7 @@ > Syntax reference:【[Beetl-Condition Control](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)】 > Due to the difference in configuration of `Beetl` in `ngbatis`, the `<% %>` will be replaced by `@ \n`, for example: + ```diff - <%if ( aBool ) { - @@ -12,12 +13,15 @@ ``` ## Use of Ternary Expressions + - PersonDao.java + ```java Person selectByNameIfNotEmpty( String name ); ``` - PersonDao.xml + ```xml <select id="selectByNameIfNotEmpty"> MATCH (n: person) @@ -29,12 +33,16 @@ ``` ## Use of if + - PersonDao.java + ```java // params = { age: 18 } Person selectByNameAndAge( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByNameAndAge"> MATCH (n: person) @@ -49,14 +57,18 @@ LIMIT 1 </select> ``` + ## Use of if-else + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -72,13 +84,16 @@ ``` ## Use of switch-case + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -97,16 +112,20 @@ LIMIT 1 </select> ``` + - > **Attention**: the switch variable placed here cannot be null ## Use of select case + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByGender( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -122,15 +141,17 @@ </select> ``` - ## Use of decode + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -144,5 +165,7 @@ LIMIT 1 </select> ``` + ## Conclusion -At this time, the methods that can be used for condition control are basically introduced. Judgment can only be made when inputting parameters. The return value cannot be controlled by conditions. \ No newline at end of file + +At this time, the methods that can be used for condition control are basically introduced. Judgment can only be made when inputting parameters. The return value cannot be controlled by conditions. diff --git a/docs/en/md/dev-example/parameter-use.md b/docs/en/md/dev-example/parameter-use.md index a388d73c..c2296345 100644 --- a/docs/en/md/dev-example/parameter-use.md +++ b/docs/en/md/dev-example/parameter-use.md @@ -7,15 +7,20 @@ Next, in this section, we will introduce how to pass parameters to the statement ## Read Parameters in `nGQL | cypher` ### Named Parameters +> > The parameters are annotated by @Param. ( org.springframework.data.repository.query.Param ) +> #### Basic Types + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("name") String param ); ``` - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -26,12 +31,16 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` #### POJO or Map + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("person") Person person ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -40,20 +49,24 @@ Next, in this section, we will introduce how to pass parameters to the statement LIMIT 1 </select> ``` + > Parameter reading supports `.` operator ### Anonymous Parameters + - If there is no @Param annotation in the parameters declared in the interface, the index is used to obtain, that is: $p0、$p1、$p2、$p3 ... - When the length of the parameter list is 1 and the type is POJO or Map, the attribute can be read directly +#### Basic Type -#### Basic Types - PersonDao.java + ```java Person selectByName( String name ); ``` - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -64,12 +77,17 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` #### POJO or Map -##### When there is only one parameter: + +##### When there is only one parameter + - PersonDao.java + ```java Person selectByName( Person person ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -79,13 +97,17 @@ Next, in this section, we will introduce how to pass parameters to the statement </select> ``` -##### When there are two or more parameters: +##### When there are two or more parameters + - PersonDao.java + ```java // params = { age: 18 } Person selectByName( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -96,16 +118,22 @@ Next, in this section, we will introduce how to pass parameters to the statement </select> ``` -### The parameter acquisition of the collection type is consistent with the basic types. +### The parameter acquisition of the collection type is consistent with the basic types + - When anonymous, use $p0,$p1,...; - When naming, directly use the parameter name in the annotation; - If it is a collection of basic types, it can be directly passed in without complex processing. + --- + - PersonDao.java + ```java List<Person> findByIds( List<String> names ); ``` + - PersonDao.xml + ```xml <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -115,4 +143,5 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` ## Conclusion + This completes the general introduction of parameter acquisition. If you have requirements for condition control and traversal after obtaining parameters, please move to【[Param Condition Control](./parameter-if)】、【[Param Loop](./parameter-for)】 diff --git a/docs/en/md/dev-example/prepare.md b/docs/en/md/dev-example/prepare.md index 5a07f3b9..02348f84 100644 --- a/docs/en/md/dev-example/prepare.md +++ b/docs/en/md/dev-example/prepare.md @@ -3,13 +3,12 @@ ## Summary Ngbatis provides two ways for developers to access nebula. + - Close to Mybatis-plus, providing a basic `DAO` to be extends, unnecessary to write any `nGQL` to operate single table, include vertex and edge. (See [By Basic DAO](./dao-basic) for more details) - Close to Mybatis, supporting developers to write complex `nGQL` or `Cypher` to finish read or write data. (See [By Custom nGQL](./custom-crud) for more details) - Take `Person` 与 `Like` as examples. - ## Create Schema in Nebula (refer [CREATE TAG](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/10.tag-statements/1.create-tag/)、[CREATE EDGE](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/11.edge-type-statements/1.create-edge/)、[CREATE INDEX](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/14.native-index-statements/1.create-native-index/)) ```sql @@ -33,7 +32,9 @@ CREATE TAG INDEX `i_person_name` on `person`(`name`(50)); ``` ## Necessary `POJO` for two ways' + ### Person.java + ```java package your.domain; @@ -56,6 +57,7 @@ public class Person { ``` ### Like.java + ```java package your.domain; @@ -71,6 +73,7 @@ public class Like { ``` ### LikeWithRank.java + ```java package your.domain; @@ -86,4 +89,4 @@ public class LikeWithRank { } ``` -By now, the 'POJO' used in the two usage examples has been created. Let's start our coding journey. \ No newline at end of file +By now, the 'POJO' used in the two usage examples has been created. Let's start our coding journey. diff --git a/docs/en/md/quick-start/about.md b/docs/en/md/quick-start/about.md index b6da3a1b..d6a3effe 100644 --- a/docs/en/md/quick-start/about.md +++ b/docs/en/md/quick-start/about.md @@ -1,19 +1,23 @@ -[![LOGO](./light.png)](https://github.com/nebula-contrib/ngbatis) +<a href="https://github.com/nebula-contrib/ngbatis"><img src="./light.png" alt="LOGO"></a> + # About Ngbatis ## How to position ngbatis + **NGBATIS** is a database ORM framework base [Nebula Graph](https://github.com/vesoft-inc/nebula) + springboot. Take advantage of [mybatis'](https://github.com/mybatis/mybatis-3) usage habits to develop. Including some frequently-used operation in single table and vertex-edge, like [mybatis-plus](https://github.com/baomidou/mybatis-plus). If you prefer JPA, [graph-ocean](https://github.com/nebula-contrib/graph-ocean) is a good choice. > If you don't have your own Nebula Graph Database, please arrange it for yourself. [Lucky Gate](https://docs.nebula-graph.com.cn/3.2.0/4.deployment-and-installation/2.compile-and-install-nebula-graph/3.deploy-nebula-graph-with-docker-compose/) ## Relevant technologies of key steps + - Database:[Nebula Graph](https://github.com/vesoft-inc/nebula) - Dynamic Proxy Framework:[ASM](https://gitlab.ow2.org/asm/asm/) `v8.0` - Mapper file parser:[jsoup](https://github.com/jhy/jsoup) `v1.12.1` - nGQL Template:[Beetl](https://github.com/javamonkey/beetl2.0) `v3.1.8.RELEASE` ## Environmental requirements + - Java 8+ -- Springboot \ No newline at end of file +- Springboot diff --git a/docs/en/md/quick-start/install.md b/docs/en/md/quick-start/install.md index 94c0febd..110b328c 100644 --- a/docs/en/md/quick-start/install.md +++ b/docs/en/md/quick-start/install.md @@ -1,6 +1,7 @@ # Import and Config -## Adding in `pom.xml`: +## Adding in `pom.xml` + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -10,6 +11,7 @@ ``` ## Adding data source configuration in `application.yml` + ```yml nebula: hosts: 127.0.0.1:19669, ip:port, .... @@ -28,27 +30,31 @@ nebula: ``` ## Import ngbatis bean + ### Nebula only, in your project + ```java @SpringBootApplication( exclude={ DataSourceAutoConfiguration.class }, scanBasePackages = { "your.domain", "org.nebula.contrib" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` + ### Multi database including Nebula + ```java @SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` @@ -56,6 +62,7 @@ public class YourSpringbootApplication { ### Primary key generator #### Declare primary key generator + ```java import org.nebula.contrib.ngbatis.PkGenerator; @@ -71,6 +78,7 @@ public class CustomPkGenerator implements PkGenerator { ``` #### Register primary key generator as bean + ```java @Configuration public class PkGeneratorConfig { diff --git a/docs/en/md/step-forward-docs/advanced-configuration.md b/docs/en/md/step-forward-docs/advanced-configuration.md index b934a937..7eb450e7 100644 --- a/docs/en/md/step-forward-docs/advanced-configuration.md +++ b/docs/en/md/step-forward-docs/advanced-configuration.md @@ -1,5 +1,8 @@ + # Advanced Configuration + ## How to display SQL on the console + ```yml logging: level: @@ -7,6 +10,7 @@ logging: ``` ## How to change location of XXXDao.xml + ```yml cql: parser: @@ -15,6 +19,7 @@ cql: ``` ## How to modify the statement of the NebulaBasicDao + ```yml cql: parser: @@ -24,10 +29,11 @@ cql: ``` ## When writing statements in XML, what if `if` and `for` are involved and @if / @for is not preferred + ```yaml cql: parser: # If you are not used to using @if or @for in the template, you can replace the delimiter by yourself statement-start: <% # default: @ statement-end: %> # default: null -``` \ No newline at end of file +``` diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index 9907a514..2a7ede55 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -1,4 +1,5 @@ # Operatior Sequence + ## Initialization process at service startup ```mermaid @@ -39,6 +40,7 @@ sequenceDiagram ``` ## When the proxy method is called + ```mermaid sequenceDiagram XXXDao->>MapperProxy: invoke( namespace, methodName, args ) @@ -58,4 +60,3 @@ sequenceDiagram MapperProxy_invoke->>MapperProxy: MapperProxy->> XXXDao: The result corresponding to the XML return value type ``` - diff --git a/docs/zhCn/md/dev-example/built-in-function.md b/docs/zhCn/md/dev-example/built-in-function.md index 1e98fea0..4995e416 100644 --- a/docs/zhCn/md/dev-example/built-in-function.md +++ b/docs/zhCn/md/dev-example/built-in-function.md @@ -1,6 +1,7 @@ # Ngbatis内置函数与变量 ## 如何使用内置函数与变量 + ```java package your.domain; @@ -8,6 +9,7 @@ public interface PersonDao { void insertPerson( Person person ); } ``` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -25,24 +27,24 @@ public interface PersonDao { </mapper> ``` + > 此出用到了 `ng.kv`、`ng.id`、`ng.tagName`、`ng.join`、`ng.schemaFmt`等内置函数,用到了`ng_args`内置参数。 > 了解了使用的地方之后,咱们在往下的内容中,将对函数进一步介绍。 - ## 内置变量 + - ng_cm ClassModel Dao接口的类模型,便于在xml中拿到更多类信息 (1.1.0-rc) - ng_mm MethodModel Dao接口中某个方法的模型,便于在xml中拿到方法信息,包括入参类型。(1.1.0-rc) - ng_args 传入Dao接口的原始参数,未序列化前。(1.1.0-rc) ## 内置函数 - - ng.valueFmt > 对不定类型的数据值进行格式化,忽略是否追加单引号及日期格式化,直接传原始 java类型即可 参数位 | 参数说明 | 类型 | 是否必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y | + 1 | 值 | Object | Y | 2 | 如果是字符串是否在前后追加 .* 形成模糊查询 | boolean | N | false > 自 v1.1.2 起,默认对字符串类型进行转义,可使用:`ValueFmtFn.setEscape( false )` 进行关闭 @@ -58,17 +60,15 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 与Schema对应的实体类对象 | Object | Y + 1 | 与Schema对应的实体类对象 | Object | Y 2 | 类模型,使用 `ng_cm` 传入 | ClassModel | N | null - - - ng.pkField > 用于获取 主键属性,java.lang.reflect.Field 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类类型 | Class<?> | Y + 1 | 实体类类型 | Class<?> | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | false - ng.pkName @@ -76,7 +76,7 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.entityType @@ -85,14 +85,14 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y - ng.fieldNames > 获取属性名集合(不包括主键) 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.id @@ -100,12 +100,13 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | true 3 | 如果值为空,true会通过主键生成器返回新值,false 时 返回空 | Boolean | N | true - ng.kv > 通过实体对象或者获取多个集合 + > > - columns 列名集合 > - valueNames 属性名集合 > - values 值集合 @@ -113,7 +114,7 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 参数名前缀 | String | N | null 3 | 是否排除主键 | Boolean | N | true 4 | 是否排除空值 | Boolean | N | true @@ -124,25 +125,23 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 待格式化的集合 | Iterable | Y - 2 | 元素间的分隔符 | String | N | `,` + 1 | 待格式化的集合 | Iterable | Y + 2 | 元素间的分隔符 | String | N | `,` 3 | 函数名,各元素拼接前,可进行函数名指定的格式化函数先行格式化,再拼接 | String | N | null - - ng.ifStringLike > 类型为字符串时,前后拼接 `.*` 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y + 1 | 值 | Object | Y 2 | 属性类型 | Object | N | null 3 | 属性名,用于不将值明文写在 ngql 中,而使用参数名,让 nebula 在参数中取值 | String | N | null - - ng.include > 引用nGQL片段 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|-------------------------------------------------------------------------------------------|---------|---|--- 1 | 要引用的nGQL片段ID.<br/>引用其他mapper的nGQL片段,片段ID前需要加上片段所在的namespace,例:your.domain.TestDao.nGQL-ID | String | Y - 2 | 引用nGQL片段时额外的参数,在生成语句时优先使用额外参数 | Object | N | null \ No newline at end of file + 2 | 引用nGQL片段时额外的参数,在生成语句时优先使用额外参数 | Object | N | null diff --git a/docs/zhCn/md/dev-example/custom-crud.md b/docs/zhCn/md/dev-example/custom-crud.md index 95725ceb..63f5e69b 100644 --- a/docs/zhCn/md/dev-example/custom-crud.md +++ b/docs/zhCn/md/dev-example/custom-crud.md @@ -2,9 +2,11 @@ - > 使用此方式的时候,对 nGQL、cypher 的熟悉度要求会高一些。还不太熟悉的开发者,可以通过【[什么是nGQL](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/1.nGQL-overview/1.overview/)】进行了解。 - > 另外提一下:这边使用的模板引擎是Beetl - > - [Beetl官方文档](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947),主要看占位符。ngbatis已经做好了变量设置,如果只是参数填充,可以忽略定界符的使用。 + > + > - [Beetl官方文档](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947),主要看占位符。ngbatis已经做好了变量设置,如果只是参数填充,可以忽略定界符的使用。 【例子详见[如何传入参数](./parameter-use)】 但,参数条件控制跟参数循环定界符几乎不可避免。因`ngbatis`关于`beetl`配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @ \n,如: +> > ```diff > - <%if ( aBool ) { > - @@ -13,16 +15,18 @@ > + > + @} > ``` - > - [Beetl文档-用于处理参数的函数](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) +> + > - [Beetl文档-用于处理参数的函数](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) > - [Beetl文档-条件控制](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)【例子详见[参数条件控制](./parameter-if)】 > - [Beetl文档-循环语句](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)【例子详见[参数遍历](./parameter-for)】 > - [Beetl在线测试小工具](http://ibeetl.com/beetlonline/) - 与[使用基类读写](./dao-basic)相同,需要编写一个 XXXDao.java 文件与 XXXDao.xml 文件。 ## 新建文件 + ### 创建一个Person对应的Dao,如果不需要用到基类方法,可以不继承 NebulaDaoBasic + ```java package your.domain; @@ -34,26 +38,32 @@ public interface PersonDao { ``` ### 创建一个名为 PersonDao.xml 的文件,默认位置为:`/resources/mapper` + ```xml <!-- 如果 space 与 yml 中声明的一致,可不写 --> <mapper namespace="your.domain.PersonDao" space="test"> </mapper> ``` + > XXXDao.java 无需经过 @Mapper 或者 @Component 进行注解,而是通过 namespace 进行发现,并自动注册成 Bean。 > 前提是:namespace 需要在 @SpringBootApplication 注解下的 scanBasePackages 值中。 > 如:@SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) ## 如何让 java 程序通过 ngbatis 执行 nGQL | cypher -### 以一个简单的查询语句为例: +### 以一个简单的查询语句为例 + #### 在 PersonDao.java 中追加接口 + ```java Integer select1(); ``` + > 目前版本中,接口的返回值类型与方法参数类型,如果是基本类型,仅支持包装类,如 int 请写成 Integer。 #### 在 PersonDao.xml 中新增一个标签 + ```xml <!-- 如果 space 与 yml 中声明的或 mapper 的 space 一致,可不写 --> <select id="select1" space="test"> @@ -64,10 +74,13 @@ public interface PersonDao { > Integer result = personDao.select1(); // result : 1 ## 引用一个nGQL片段 +> > 像MyBatis的include标签一样引用一段语句。 NgBatis使用内置函数`ng.include`实现引用,`ng.include`的说明可见[Ngbatis内置函数与变量](./built-in-function) + ### 定义Dao接口 + ```java package your.domain; @@ -82,7 +95,9 @@ public interface TestDao { } ``` + ### 编写对应的xml文件,并定义nGQL片段和接口方法语句 + ```xml <!-- 如果 space 与 yml 中声明的一致,可不写 --> <mapper namespace="your.domain.TestDao" space="test"> @@ -108,8 +123,9 @@ public interface TestDao { </mapper> ``` + nGQL片段自动继承Dao方法所传入的参数,可以在nGQL片段内直接使用,也可以在`ng.include`函数上指定额外参数,在生成语句时优先使用额外参数,参考上方例子。 nGQL片段不限层级,nGQL片段也可以引用nGQL片段,考虑到性能,不建议过多层级的nGQL语句引用。 -如果需要引用其他mapper内的nGQL片段,使用`ng.include`函数时需要在片段ID前面拼接上片段所在的namespace,如:`@ng.include('your.domain.XxxDao.nGQL-ID');` \ No newline at end of file +如果需要引用其他mapper内的nGQL片段,使用`ng.include`函数时需要在片段ID前面拼接上片段所在的namespace,如:`@ng.include('your.domain.XxxDao.nGQL-ID');` diff --git a/docs/zhCn/md/dev-example/dao-basic.md b/docs/zhCn/md/dev-example/dao-basic.md index 64f880d7..74462b44 100644 --- a/docs/zhCn/md/dev-example/dao-basic.md +++ b/docs/zhCn/md/dev-example/dao-basic.md @@ -1,6 +1,7 @@ # 使用基类读写 ## 创建一个Person对应的Dao,并继承 NebulaDaoBasic + ```java package your.domain; @@ -12,6 +13,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## 创建一个名为 PersonDao.xml 的文件,默认位置为:`/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -19,6 +21,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## 在 Service 层中举例 + ```java @Service diff --git a/docs/zhCn/md/dev-example/multi-tag.md b/docs/zhCn/md/dev-example/multi-tag.md index 31db9927..a0f3d618 100644 --- a/docs/zhCn/md/dev-example/multi-tag.md +++ b/docs/zhCn/md/dev-example/multi-tag.md @@ -1,10 +1,12 @@ # 基类实现多标签 ^v1.1.2 ## 实现的效果 + - insert时可以一次同时将 Person 和 Employee 的属性写入数据库 - select时可以一次同时将 Person 和 Employee 的属性读出,但如果该节点具备其他标签,则不会读出 ## 实体类 + ```java @Data @Table(name = "employee") @@ -16,6 +18,7 @@ public class Employee extends Person { > DAO的实现方式与单标签的实现方式一致 ## DAO + ```java import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; @@ -26,8 +29,9 @@ public interface EmployeeDao extends NebulaDaoBasic<Employee, String> { ``` ## DAO XML + ```xml <mapper namespace="your.domain.repository.EmployeeDao"> </mapper> -``` \ No newline at end of file +``` diff --git a/docs/zhCn/md/dev-example/parameter-for.md b/docs/zhCn/md/dev-example/parameter-for.md index f156df3a..1accbea8 100644 --- a/docs/zhCn/md/dev-example/parameter-for.md +++ b/docs/zhCn/md/dev-example/parameter-for.md @@ -2,6 +2,7 @@ > 遍历的部分跟 mybatis 的差异比较大,使用了 Beetl 的遍历语法。具体可参考官方文档【[1.10 循环语句](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)】 > 因配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @ \n,如: + ```diff - <%for ( item in list ) { - @@ -12,7 +13,9 @@ ``` ## 对Map的遍历,可用于动态查询 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // person: { "name": "张三", "gender": "F" } @@ -20,6 +23,7 @@ ``` - PersonDao.xml + ```xml <select id="selectByPerson"> MATCH (n: person) @@ -37,6 +41,7 @@ ## 对 List 遍历,可用于批处理 - PersonDao.java + ```java // org.springframework.data.repository.query.Param // personList: [{"gender":"F","name":"张三"},{"gender":"M","name":"王五"},{"gender":"F","name":"赵六"}] @@ -44,11 +49,13 @@ ``` - 参数为: + ```json :param personList => [{"gender":"F","name":"张三"},{"gender":"M","name":"王五"},{"gender":"F","name":"赵六"}] ``` - PersonDao.xml + ```xml <insert id="insertPersonList"> @for ( p in personList ) { @@ -58,6 +65,7 @@ ``` - 执行的语句为: + ```sql INSERT VERTEX `person` ( name, gender ) VALUES '张三' : ( '张三', 'F' ); INSERT VERTEX `person` ( name, gender ) VALUES '王五' : ( '王五', 'M' ); diff --git a/docs/zhCn/md/dev-example/parameter-if.md b/docs/zhCn/md/dev-example/parameter-if.md index 3899bd19..b960dfe8 100644 --- a/docs/zhCn/md/dev-example/parameter-if.md +++ b/docs/zhCn/md/dev-example/parameter-if.md @@ -2,6 +2,7 @@ > 语法参考【[Beetl 条件控制](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)】 > 因配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @,如: + ```diff - <%if ( aBool ) { - @@ -12,12 +13,15 @@ ``` ## 三元表达式的使用 + - PersonDao.java + ```java Person selectByNameIfNotEmpty( String name ); ``` - PersonDao.xml + ```xml <select id="selectByNameIfNotEmpty"> MATCH (n: person) @@ -29,12 +33,16 @@ ``` ## if 的使用 + - PersonDao.java + ```java // params = { age: 18 } Person selectByNameAndAge( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByNameAndAge"> MATCH (n: person) @@ -49,14 +57,18 @@ LIMIT 1 </select> ``` + ## if-else 的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -72,13 +84,16 @@ ``` ## switch case的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -97,16 +112,20 @@ LIMIT 1 </select> ``` + - > **注意**: 此处放入 switch 的变量,不可为 null ## select case 的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByGender( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -122,15 +141,17 @@ </select> ``` - ## decode 函数的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -144,5 +165,7 @@ LIMIT 1 </select> ``` + ## 总结 -到此,可用于条件判断的方式基本介绍完成。只能用于入参时的判断。返回值不能使用条件控制。 \ No newline at end of file + +到此,可用于条件判断的方式基本介绍完成。只能用于入参时的判断。返回值不能使用条件控制。 diff --git a/docs/zhCn/md/dev-example/parameter-use.md b/docs/zhCn/md/dev-example/parameter-use.md index fc706581..6f20871f 100644 --- a/docs/zhCn/md/dev-example/parameter-use.md +++ b/docs/zhCn/md/dev-example/parameter-use.md @@ -4,17 +4,21 @@ 接下来,将在当前部分介绍如何对自己编写的语句进行传参。 > **注意**:所有参数基本类型目前只支持包装类,如 int 需要写成 Integer。 - ## 在 `nGQL | cypher` 中读取参数 ## 具名参数 +> > 参数被 @Param 所注解。org.springframework.data.repository.query.Param +> #### 简单类型 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("name") String param ); ``` + - PersonDao.xml ::: code-group @@ -27,6 +31,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -44,14 +49,18 @@ LIMIT 1 </select> ``` + ::: #### POJO 或 Map + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("person") Person person ); ``` + - PersonDao.xml ::: code-group @@ -63,6 +72,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -80,16 +90,20 @@ LIMIT 1 </select> ``` + ::: + > 参数读取支持 `.` 运算符,如果是 POJO 或 Map,可以直接读取内部属性 ## 匿名参数 + - 如果在接口中声明的参数中,不带 @Param 注解,则使用下标位进行获取,即 ${ p0 }、${ p1 }、${ p2 }、${ p3 } ... 或 $p0、$p1、$p2、$p3 ... - 参数列表长度为1,类型为 POJO 或 Map 时,可直接读取属性 - #### 基本类型 + - PersonDao.java + ```java Person selectByName( String name ); ``` @@ -105,6 +119,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -113,6 +128,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -123,12 +139,17 @@ ``` ::: + #### POJO 或 Map -##### 参数只有一个时: + +##### 参数只有一个时 + - PersonDao.java + ```java Person selectByName( Person person ); ``` + - PersonDao.xml ::: code-group @@ -140,6 +161,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -148,6 +170,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -156,14 +179,18 @@ LIMIT 1 </select> ``` + ::: -##### 参数有两个及以上时: +##### 参数有两个及以上时 + - PersonDao.java + ```java // params = { age: 18 } Person selectByName( Person person, Map<String, Object> params ); ``` + - PersonDao.xml ::: code-group @@ -176,6 +203,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -185,6 +213,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -194,17 +223,23 @@ LIMIT 1 </select> ``` + ::: -## 集合类型的参数获取,与基本类型一致。 +## 集合类型的参数获取,与基本类型一致 + - 匿名时,使用 ${ p0 }、${ p1 },或 $p0、$p1... - 具名时,直接使用注解内的参数名 - 如果是基本类型的集合,不需要做复杂处理,可以直接传入 + --- + - PersonDao.java + ```java List<Person> findByIds( List<String> names ); ``` + - PersonDao.xml ::: code-group @@ -215,6 +250,7 @@ RETURN n </select> ``` + ```xml [方式2] <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -222,6 +258,7 @@ RETURN n </select> ``` + ```xml [参数由 DB 替换] <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -232,13 +269,14 @@ ::: - ## 常见问题 + - 两种占位符格式: - - `${ 参数名.子参数名 }` ngbatis 的占位符,执行到数据库前完成替换 - - `$参数名.子参数名` NebulaGraph 的占位符,由数据库完成替换,但需要注意支持参数化的位置。 + - `${ 参数名.子参数名 }` ngbatis 的占位符,执行到数据库前完成替换 + - `$参数名.子参数名` NebulaGraph 的占位符,由数据库完成替换,但需要注意支持参数化的位置。 - 特殊符号问题: - - 可以使用内置函数进行转义 `${ ng.valueFmt( 参数名 ) }`,该函数同样无需判断数据类型。如是字符串也无需加前后引号 + - 可以使用内置函数进行转义 `${ ng.valueFmt( 参数名 ) }`,该函数同样无需判断数据类型。如是字符串也无需加前后引号 ## 总结 + 到此,关于参数获取的大致介绍完毕。如果有关于获取参数后的条件控制以及遍历的需求,请移步【[参数条件控制](./parameter-if)】、【[参数遍历](./parameter-for)】 diff --git a/docs/zhCn/md/dev-example/prepare.md b/docs/zhCn/md/dev-example/prepare.md index 99304679..7d251078 100644 --- a/docs/zhCn/md/dev-example/prepare.md +++ b/docs/zhCn/md/dev-example/prepare.md @@ -1,13 +1,13 @@ # 准备工作 ## 大致介绍 + Ngbatis 提供了两种方式为开发者提供便利 + - 类似于 Mybatis-plus 的方式,提供一个基类让业务的`DAO`进行继承,不需要自己写 `nGQL` 就能完成单顶点、单边的增删改查。 (详见[使用基类编写](./dao-basic)) - 类似于 Mybatis 的方式,支持自己编写复杂的 `nGQL` 或 `Cypher` 来完成复杂的业务查询与数据写入。(详见[自定义nGQL](./custom-crud)) - - 下面,以 `Person` 与 `Like` 为例。 ## Nebula Graph 中创建的 Schema (参考[CREATE TAG](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/10.tag-statements/1.create-tag/)、[CREATE EDGE](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/11.edge-type-statements/1.create-edge/)、[CREATE INDEX](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/14.native-index-statements/1.create-native-index/)) @@ -32,7 +32,9 @@ CREATE TAG INDEX `i_person_name` on `person`(`name`(50)); ``` ## 两种方式都需要的 `POJO` 类 + ### Person.java + ```java package your.domain; @@ -61,6 +63,7 @@ public class Person { ``` ### Like.java + ```java package your.domain; @@ -76,6 +79,7 @@ public class Like { ``` ### LikeWithRank.java + ```java package your.domain; @@ -91,4 +95,4 @@ public class LikeWithRank { } ``` -到此,两种使用方式样例所用的 `POJO` 就已经创建完毕。接下来开始我们的介绍。 \ No newline at end of file +到此,两种使用方式样例所用的 `POJO` 就已经创建完毕。接下来开始我们的介绍。 diff --git a/docs/zhCn/md/dev-example/result-built-in.md b/docs/zhCn/md/dev-example/result-built-in.md index ceafb621..eab15c7c 100644 --- a/docs/zhCn/md/dev-example/result-built-in.md +++ b/docs/zhCn/md/dev-example/result-built-in.md @@ -2,8 +2,8 @@ 如果项目中不建立实体,都是动态查询的话,可以考虑使用内置的返回值类型。数据结构如下: - ## NgVertex + ```json { "properties":{ // Map, key 是 tag 名称,keys 的长度与本级的 tags 的长度一致 @@ -20,6 +20,7 @@ ``` ## NgEdge + ```json { "dstID":"1670225547548", @@ -33,6 +34,7 @@ ``` ## NgSubgraph + ```json { "edges":[ @@ -60,4 +62,4 @@ } ] } -``` \ No newline at end of file +``` diff --git a/docs/zhCn/md/dev-example/result.md b/docs/zhCn/md/dev-example/result.md index 6a3ca003..d48c94f8 100644 --- a/docs/zhCn/md/dev-example/result.md +++ b/docs/zhCn/md/dev-example/result.md @@ -1,28 +1,41 @@ # 不同返回值类型 + 从nebula获得结果后,往往并不能获得业务所需的结果类型,此时,开发者需要告知 ngbatis 具体业务所需的类型。 ## 原始类型 [ResultSet](https://github.com/vesoft-inc/nebula-java/blob/master/client/src/main/java/com/vesoft/nebula/client/graph/data/ResultSet.java) (com.vesoft.nebula.client.graph.data.ResultSet) + 如果接口返回值为 nebula 的 ResultSet,ngbatis 不做任何处理,直接返回跟调用方,由开发者在调用方中自行处理结果集。 + - PersonDao.java + ```java ResultSet returnResultSet(); ``` + - PersonDao.xml + ```xml <select id="returnResultSet"> RETURN 'You are best' </select> ``` + - > 如果在下列的几种类型中,不能满足开发所需的结果集处理,可以使用获取原始ResultSet类型的返回值,并自行做灵活处理。可阅读[ResultSet源码](https://github.com/vesoft-inc/nebula-java/blob/master/client/src/main/java/com/vesoft/nebula/client/graph/data/ResultSet.java)做近一步了解。 ## 非集合类型 + 此时,结果类型已经通过 方法的返回值类型告知 ngbatis,所以无需额外的配置,即可完成类型映射。 + ### 基本类型 + - PersonDao.java + ```java String returnString(); ``` + - PersonDao.xml + ```xml <select id="returnString"> RETURN 'You are best' @@ -30,12 +43,16 @@ ``` ### POJO | Map + - PersonDao.java + ```java Person returnFirst(); // 或者 Map returnFirst(); ``` + - PersonDao.xml + ```xml <select id="returnFirst"> MATCH (n: person) @@ -43,7 +60,9 @@ LIMIT 1 </select> ``` + - json序列化后,结果为: + ```json { "name": "张三", @@ -53,17 +72,22 @@ } ``` - ## 集合类型 + 因为运行时,方法在字节码中的集合泛型丢失,因此需要通过标签中的 `resultType` 属性告知 ngbatis,多行中单行结果的类型。 + ### 单栏位返回值 #### 基本类型 + - PersonDao.java + ```java List<String> returnNameTop10(); ``` + - PersonDao.xml + ```xml <select id="returnNameTop10" resultType="java.lang.String"> MATCH (n: person) @@ -71,14 +95,19 @@ LIMIT 10 </select> ``` + - json序列化后,结果为:[ "张三", "李四", ... ] #### POJO + - PersonDao.java + ```java List<Person> returnTop10(); ``` + - PersonDao.xml + ```xml <select id="returnTop10" resultType="your.domain.Person"> MATCH (n: person) @@ -86,7 +115,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -98,14 +129,19 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射到实体类属性 #### Map + - PersonDao.java + ```java List<Map> returnTop10(); ``` + - PersonDao.xml + ```xml <select id="returnTop10" resultType="java.util.Map"> MATCH (n: person) @@ -113,7 +149,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -125,15 +163,21 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射做为 map 的 key ### 多栏位返回值 + #### POJO + - PersonDao.java + ```java List<Person> returnPartTop10(); ``` + - PersonDao.xml + ```xml <select id="returnPartTop10" resultType="your.domain.Person"> MATCH (n: person) @@ -143,7 +187,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -156,13 +202,16 @@ ] ``` - #### Map + - PersonDao.java + ```java List<Map> returnPartTop10(); ``` + - PersonDao.xml + ```xml <select id="returnPartTop10" resultType="java.util.Map"> MATCH (n: person) @@ -172,7 +221,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -182,12 +233,17 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射做为 map 的 key ## 复合对象类型(Path类型处理方式,三元组) + **注意**:下列例子是当前版本处理 Path 结果集的举例 -### 声明复合对象类: - - NRN2.java + +### 声明复合对象类 + +- NRN2.java + ```java package your.domain; @@ -197,12 +253,17 @@ private Person n2; } ``` + ### 非集合类型 - - PersonDao.java + +- PersonDao.java + ```java NRN2 returnFirstRelation(); ``` - - PersonDao.xml + +- PersonDao.xml + ```xml <select id="returnFirst"> MATCH (n: person)-[r: like]->(n2: person) @@ -210,12 +271,17 @@ LIMIT 1 </select> ``` + ### 集合类型 - - PersonDao.java + +- PersonDao.java + ```java List<NRN2> returnRelationTop10(); ``` - - PersonDao.xml + +- PersonDao.xml + ```xml <select id="returnRelationTop10" resultType="your.domain.NRN2"> MATCH (n: person)-[r: like]->(n2: person) @@ -223,4 +289,5 @@ LIMIT 10 </select> ``` - - > 使用 List<Map\> 做为返回值同样奏效,n, r, n2 为 map 的 key + +- > 使用 List<Map\> 做为返回值同样奏效,n, r, n2 为 map 的 key diff --git a/docs/zhCn/md/quick-start/about.md b/docs/zhCn/md/quick-start/about.md index 658f7981..f6ae6ee0 100644 --- a/docs/zhCn/md/quick-start/about.md +++ b/docs/zhCn/md/quick-start/about.md @@ -3,17 +3,20 @@ # 关于 Ngbatis ## 应用程序中的定位 + **NGBATIS** 是一款针对 [Nebula Graph](https://github.com/vesoft-inc/nebula) + Springboot 的数据库 ORM 框架。借鉴于 [MyBatis](https://github.com/mybatis/mybatis-3) 的使用习惯进行开发。包含了一些类似于[mybatis-plus](https://github.com/baomidou/mybatis-plus)的单表操作,另外还有一些图特有的实体-关系基本操作。 如果使用上更习惯于JPA的方式,[graph-ocean](https://github.com/nebula-contrib/graph-ocean) 是个不错的选择。 > 如果你还没有属于自己的 Nebula 图数据库,请给自己安排上。[安装传送门](https://docs.nebula-graph.com.cn/3.2.0/4.deployment-and-installation/2.compile-and-install-nebula-graph/3.deploy-nebula-graph-with-docker-compose/) ## 关键环节的相关技术 + - 数据库:[Nebula Graph](https://github.com/vesoft-inc/nebula) - 动态代理生成框架:[ASM](https://gitlab.ow2.org/asm/asm/) `v8.0` - mapper文件解析:[jsoup](https://github.com/jhy/jsoup) `v1.12.1` - nGQL模板:[Beetl](https://github.com/javamonkey/beetl2.0) `v3.1.8.RELEASE` ## 环境要求 + - Java 8+ -- Springboot \ No newline at end of file +- Springboot diff --git a/docs/zhCn/md/quick-start/features.md b/docs/zhCn/md/quick-start/features.md index a3a2971c..10de31bc 100644 --- a/docs/zhCn/md/quick-start/features.md +++ b/docs/zhCn/md/quick-start/features.md @@ -1,9 +1,11 @@ # 框架特性 ## 一、集成 + - [x] 支持通过简单配置,快速完成 Nebula Graph 与 Springboot 的整合 ## 二、单表(Vertex、Edge)操作,无需写 `nGQL | cypher` +> > 用法参见【[使用基类编写](../dev-example/dao-basic)】 API | 用法说明 @@ -12,7 +14,7 @@ selectById(ID id) | 通过主键获取节点 selectByIds(Collection<I\> ids) | 根据 id 集合获取节点 selectBySelective(T entity) | 按实体属性值查询 selectIdBySelectiveStringLike(T entity) | 根据实体属性值查询,字符串属性使用模糊查询 -selectByMap(Map<String, Object\> param) | 根据 map 参数查询 +selectByMap(Map<String, Object\> param) | 根据 map 参数查询 countByMap(Map<String, Object\> param) | 根据 map 参数统计条数 selectPage(Page<T\> page) | 分页查询 insert(T entity) | 插入 Vertex,空值覆盖 @@ -30,33 +32,35 @@ listStartNodes(Class<E\> startType, Class edgeType, ID endId) | 查找一个节 startNode(Class edgeType, ID endId) | 查找一个节点中,某种关系的唯一一个上游节点 startNode(Class<E\> startType, Class edgeType, ID endId) | 查找查找一个节点特定类型的上游节点 - - ## 三、使用 xml 的方式,集中管理 `nGQL | cypher` +> > 用法参见【[自定义nGQL](../dev-example/custom-crud)】 扫描指定资源包,并获得 `nGQL | cypher` 模板,在模板的基础上做操作。 ### (一) 参数替换 + - [x] 使用占位符为 `nGQL | cypher` 替换参数,并执行到数据库; - 编写查询脚本模板,搭配参数控制,实现动态查询 - 通过参数循环,实现批量操作 ### (二) 通过 Dao 接口的方法签名信息,对 ResultSet 进行处理,形成业务所需类型 - - [x] 集合类型 - - Collection<基本类型> - - Collection<对象类型> `Object类型参考下述Object的支持` - - [x] 基本类型 - - String - - Boolean - - Number (Integer、Long、Float、Double、Byte、Short)。**暂时只支持包装类** - - [x] 对象类型 - - Object - - 多列return值转换成 Map - - 多列return值转换成 POJO - - 支持Vertex类型转换成 POJO - - 支持Edge类型转换成 POJO - - [x] ResultSet 如不需要使用框架自带的结果处理,可直接在接口声明返回值 ResultSet 并自行处理 + +- [x] 集合类型 + - Collection<基本类型> + - Collection<对象类型> `Object类型参考下述Object的支持` +- [x] 基本类型 + - String + - Boolean + - Number (Integer、Long、Float、Double、Byte、Short)。**暂时只支持包装类** +- [x] 对象类型 + - Object + - 多列return值转换成 Map + - 多列return值转换成 POJO + - 支持Vertex类型转换成 POJO + - 支持Edge类型转换成 POJO +- [x] ResultSet 如不需要使用框架自带的结果处理,可直接在接口声明返回值 ResultSet 并自行处理 ## 四、主键生成策略接口 + - [x] 提供主键生成器的埋点,开发者可自定义主键生成器。 diff --git a/docs/zhCn/md/quick-start/install.md b/docs/zhCn/md/quick-start/install.md index 0672ce49..d3fda09a 100644 --- a/docs/zhCn/md/quick-start/install.md +++ b/docs/zhCn/md/quick-start/install.md @@ -1,5 +1,7 @@ # 安装与使用 -## 在 `pom.xml` 中添加: + +## 在 `pom.xml` 中添加 + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -9,6 +11,7 @@ ``` ### SNAPSHOT 版本 + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -16,22 +19,24 @@ <version>1.2.0-SNAPSHOT</version> </dependency> ``` + ```xml - <repositories> - <repository> - <snapshots> - <enabled>true</enabled> - <updatePolicy>always</updatePolicy> - <checksumPolicy>warn</checksumPolicy> - </snapshots> - <id>ossrh</id> - <name>Nexus Snapshot Repository</name> - <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url> - </repository> - </repositories> + <repositories> + <repository> + <snapshots> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + <checksumPolicy>warn</checksumPolicy> + </snapshots> + <id>ossrh</id> + <name>Nexus Snapshot Repository</name> + <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url> + </repository> + </repositories> ``` -## 在 `application.yml` 配置数据源 +## 在 `application.yml` 配置数据源 + ```yml nebula: ngbatis: @@ -58,27 +63,31 @@ nebula: ``` ## 引入 ngbatis bean + ### 项目中,只用到的 Nebula Graph 数据库 + ```java @SpringBootApplication( exclude={ DataSourceAutoConfiguration.class }, scanBasePackages = { "org.nebula.contrib", "your.domain" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` + ### 项目中还有其他数据库 + ```java @SpringBootApplication( scanBasePackages = { "org.nebula.contrib", "your.domain" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` @@ -86,6 +95,7 @@ public class YourSpringbootApplication { ## 主键生成器 #### 创建并注册主键生成器 + ```java import org.nebula.contrib.ngbatis.PkGenerator; diff --git a/docs/zhCn/md/step-forward-docs/advanced-configuration.md b/docs/zhCn/md/step-forward-docs/advanced-configuration.md index 98df72c4..2b7f2920 100644 --- a/docs/zhCn/md/step-forward-docs/advanced-configuration.md +++ b/docs/zhCn/md/step-forward-docs/advanced-configuration.md @@ -1,6 +1,8 @@ # 进阶配置 -## 如何在控制台打印 sql + +## 如何在控制台打印 sql + ```yml logging: level: @@ -8,6 +10,7 @@ logging: ``` ## 如何更改 XXXDao.xml 的位置 + ```yml cql: parser: @@ -16,6 +19,7 @@ cql: ``` ## 如何修改基类的语句 + ```yml cql: parser: @@ -27,6 +31,7 @@ cql: ``` ## 在 xml 写语句时,如果涉及 if 跟 for,又不喜欢用 @if / @for 怎么办 + ```yml cql: parser: diff --git a/docs/zhCn/md/step-forward-docs/operation-sequence.md b/docs/zhCn/md/step-forward-docs/operation-sequence.md index e13fc301..1c081b4d 100644 --- a/docs/zhCn/md/step-forward-docs/operation-sequence.md +++ b/docs/zhCn/md/step-forward-docs/operation-sequence.md @@ -1,4 +1,5 @@ # 运行时序 + ## 服务启动时的初始化过程 ```mermaid @@ -39,6 +40,7 @@ sequenceDiagram ``` ## 当代理方法被调用时 + ```mermaid sequenceDiagram XXXDao->>MapperProxy: invoke( 接口名, 方法名, 参数列表 ) diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..34034d93 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,706 @@ +{ + "name": "ngbatis", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ngbatis", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "markdownlint": "^0.31.0", + "markdownlint-cli": "^0.36.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz", + "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", + "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdownlint": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.31.0.tgz", + "integrity": "sha512-e+jZGRGZrz1s0T4wiPDFtyQafq7sKgdbf2sdL46gRT8zLEvDDihQmGeSCV6VXp9BsfkuZ0dPTAg9hf4j6NFgjg==", + "dev": true, + "dependencies": { + "markdown-it": "13.0.1", + "markdownlint-micromark": "0.1.7" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.36.0.tgz", + "integrity": "sha512-h4WdqOam3+QOVOcJSOQuG8KvvN8dlS0OiJhbPwYWBk7VMZR40UtSSMIOpSP5B4EHPHg3W3ILSQUvqg1HNpTCxA==", + "dev": true, + "dependencies": { + "commander": "~11.0.0", + "get-stdin": "~9.0.0", + "glob": "~10.3.4", + "ignore": "~5.2.4", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.2.0", + "markdownlint": "~0.30.0", + "minimatch": "~9.0.3", + "run-con": "~1.3.2" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-cli/node_modules/markdownlint": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.30.0.tgz", + "integrity": "sha512-nInuFvI/rEzanAOArW5490Ez4EYpB5ODqVM0mcDYCPx9DKJWCQqCgejjiCvbSeE7sjbDscVtZmwr665qpF5xGA==", + "dev": true, + "dependencies": { + "markdown-it": "13.0.1", + "markdownlint-micromark": "0.1.7" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz", + "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..bc2f12ab --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "ngbatis", + "version": "1.0.0", + "description": "<!--\r Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved.", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "lint-md": "markdownlint *.md docs", + "format-md": "markdownlint --fix *.md docs" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "markdownlint": "^0.31.0", + "markdownlint-cli": "^0.36.0" + } +} From beeda0217454597304bbbb2c2038a1c5816aeaa4 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 12:23:33 +0800 Subject: [PATCH 11/56] fix ci node setup --- .github/workflows/markdown_lint.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/markdown_lint.yaml b/.github/workflows/markdown_lint.yaml index 556fe3b4..1b378303 100644 --- a/.github/workflows/markdown_lint.yaml +++ b/.github/workflows/markdown_lint.yaml @@ -22,7 +22,6 @@ jobs: with: node-version: 18 cache: npm - cache-dependency-path: docs/package-lock.json - name: Install dependencies and lint markdown run: | cd docs From e5035b739a4034f2f3c8eefe0d9f4e2c0336e66f Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 04:59:58 +0000 Subject: [PATCH 12/56] ci: skip javadoc in maven publish --- .github/workflows/release.yml | 1 + .github/workflows/snapshot.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de22e956..9669fa28 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,3 +37,4 @@ jobs: gpg_passphrase: ${{ secrets.GPG_PASSWORD }} nexus_username: ${{ secrets.OSSRH_USER }} nexus_password: ${{ secrets.OSSRH_PASSWORD }} + maven-goals: 'deploy -Dmaven.javadoc.skip=true' diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index b21d5079..3275a18e 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -39,3 +39,4 @@ jobs: gpg_passphrase: ${{ secrets.GPG_PASSWORD }} nexus_username: ${{ secrets.OSSRH_USER }} nexus_password: ${{ secrets.OSSRH_PASSWORD }} + maven-goals: 'deploy -Dmaven.javadoc.skip=true' From 8443a74b84c1b0538ac9c8e92c6fa2a17d48c184 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 06:08:46 +0000 Subject: [PATCH 13/56] fix maven_args in action-maven-publish@v1 --- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9669fa28..3e76b454 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,4 +37,4 @@ jobs: gpg_passphrase: ${{ secrets.GPG_PASSWORD }} nexus_username: ${{ secrets.OSSRH_USER }} nexus_password: ${{ secrets.OSSRH_PASSWORD }} - maven-goals: 'deploy -Dmaven.javadoc.skip=true' + maven_args: '-Dmaven.javadoc.skip=true' diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index 3275a18e..71f0a720 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -39,4 +39,4 @@ jobs: gpg_passphrase: ${{ secrets.GPG_PASSWORD }} nexus_username: ${{ secrets.OSSRH_USER }} nexus_password: ${{ secrets.OSSRH_PASSWORD }} - maven-goals: 'deploy -Dmaven.javadoc.skip=true' + maven_args: '-Dmaven.javadoc.skip=true' From 40c88fee3ac66af993332babc098eca60e0e8094 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Sun, 10 Sep 2023 08:13:41 +0000 Subject: [PATCH 14/56] ci drop old gh action, use mvn directly ref: - https://docs.github.com/en/actions/publishing-packages/publishing-java-packages-with-maven - https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md close: #223 --- .github/workflows/release.yml | 22 ++++++++++++++-------- .github/workflows/snapshot.yaml | 22 ++++++++++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e76b454..c365b275 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,7 +11,7 @@ jobs: - name: Check out Git repository uses: actions/checkout@v3 - - name: Install Java and Maven + - name: Setup Java uses: actions/setup-java@v3 with: java-version: '8' @@ -30,11 +30,17 @@ jobs: popd popd - - name: Release Maven package - uses: samuelmeuli/action-maven-publish@v1 + - name: Set up Apache Maven Central + uses: actions/setup-java@v3 with: - gpg_private_key: ${{ secrets.GPG_SECRET }} - gpg_passphrase: ${{ secrets.GPG_PASSWORD }} - nexus_username: ${{ secrets.OSSRH_USER }} - nexus_password: ${{ secrets.OSSRH_PASSWORD }} - maven_args: '-Dmaven.javadoc.skip=true' + java-version: '8' + distribution: 'temurin' + gpg-private-key: ${{ secrets.GPG_SECRET }} + gpg-passphrase: ${{ secrets.GPG_PASSWORD }} + + - name: Publish package + run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSWORD }} diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index 71f0a720..e09803f5 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -13,7 +13,7 @@ jobs: - name: Check out Git repository uses: actions/checkout@v3 - - name: Install Java and Maven + - name: Setup Java uses: actions/setup-java@v3 with: java-version: '8' @@ -32,11 +32,17 @@ jobs: popd popd - - name: Deploy Snapshot to Maven package - uses: samuelmeuli/action-maven-publish@v1 + - name: Set up Apache Maven Central + uses: actions/setup-java@v3 with: - gpg_private_key: ${{ secrets.GPG_SECRET }} - gpg_passphrase: ${{ secrets.GPG_PASSWORD }} - nexus_username: ${{ secrets.OSSRH_USER }} - nexus_password: ${{ secrets.OSSRH_PASSWORD }} - maven_args: '-Dmaven.javadoc.skip=true' + java-version: '8' + distribution: 'temurin' + gpg-private-key: ${{ secrets.GPG_SECRET }} + gpg-passphrase: ${{ secrets.GPG_PASSWORD }} + + - name: Publish package + run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSWORD }} From 93cd46d1daf302a1c122b8e5e2178d870bdd7a9b Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Mon, 11 Sep 2023 09:59:51 +0800 Subject: [PATCH 15/56] =?UTF-8?q?=E8=B7=AF=E5=BE=84=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=20NgPath=20=E5=A2=9E=E5=8A=A0=20=E7=82=B9?= =?UTF-8?q?=E3=80=81=E8=BE=B9=20=E7=9A=84=E8=AF=A6=E7=BB=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ngbatis/handler/NgPathResultHandler.java | 40 ++++++++++++------- .../handler/NgVertexResultHandler.java | 24 +++++++---- .../contrib/ngbatis/models/data/NgPath.java | 28 +++++++++++++ 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java index e73a1e4e..4d4f495e 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java @@ -11,6 +11,9 @@ import org.nebula.contrib.ngbatis.utils.ResultSetUtil; import org.springframework.stereotype.Component; +import javax.annotation.Resource; +import java.io.UnsupportedEncodingException; + /** * Convert the path data from ResultSet to NgPath. * @author yeweicheng @@ -20,6 +23,9 @@ @Component public class NgPathResultHandler extends AbstractResultHandler<NgPath<?>, NgPath<?>> { + @Resource + private NgVertexResultHandler ngVertexResultHandler; + @Override public NgPath<?> handle(NgPath<?> newResult, ResultSet result, Class resultType) throws NoSuchFieldException, IllegalAccessException, InstantiationException { @@ -29,20 +35,26 @@ public NgPath<?> handle(NgPath<?> newResult, ResultSet result, Class resultType) public NgPath<?> handle(NgPath<?> newResult, Record record) { PathWrapper pathWrapper = ResultSetUtil.getValue(record.values().get(0)); - - pathWrapper.getRelationships().forEach(relationship -> { - NgPath.Relationship ngRelationship = new NgPath.Relationship(); - long ranking = relationship.ranking(); - Object srcId = ResultSetUtil.getValue(relationship.srcId()); - Object dstId = ResultSetUtil.getValue(relationship.dstId()); - String edgeName = relationship.edgeName(); - - ngRelationship.setRank(ranking); - ngRelationship.setSrcID(srcId); - ngRelationship.setDstID(dstId); - ngRelationship.setEdgeName(edgeName); - - newResult.getRelationships().add(ngRelationship); + pathWrapper.getSegments().forEach(segment -> { + try { + NgPath.Relationship ngRelationship = new NgPath.Relationship(); + long ranking = segment.getRelationShip().ranking(); + Object srcId = ResultSetUtil.getValue(segment.getStartNode().getId()); + Object dstId = ResultSetUtil.getValue(segment.getEndNode().getId()); + String edgeName = segment.getRelationShip().edgeName(); + ngRelationship.setRank(ranking); + ngRelationship.setSrcID(srcId); + ngRelationship.setDstID(dstId); + ngRelationship.setEdgeName(edgeName); + ngRelationship.setProperties(ResultSetUtil.edgePropsToMap(segment.getRelationShip())); + + ngVertexResultHandler.handle(ngRelationship.getDst(), segment.getEndNode()); + ngVertexResultHandler.handle(ngRelationship.getSrc(), segment.getStartNode()); + + newResult.getRelationships().add(ngRelationship); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } }); return newResult; } diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java index 8b741889..8cf20c63 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java @@ -4,21 +4,22 @@ // // This source code is licensed under Apache 2.0 License. -import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.nodePropsToMap; - import com.vesoft.nebula.client.graph.data.Node; import com.vesoft.nebula.client.graph.data.ResultSet; import com.vesoft.nebula.client.graph.data.ResultSet.Record; import com.vesoft.nebula.client.graph.data.ValueWrapper; -import java.io.UnsupportedEncodingException; -import java.util.List; import org.nebula.contrib.ngbatis.exception.ResultHandleException; import org.nebula.contrib.ngbatis.models.data.NgVertex; import org.nebula.contrib.ngbatis.utils.ResultSetUtil; import org.springframework.stereotype.Component; +import java.io.UnsupportedEncodingException; +import java.util.List; + +import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.nodePropsToMap; + /** - * Convert the vertex data from ResultSet to NgVertex. + * Convert the vertex data from ResultSet to NgVertex. * @author yeweicheng * @since 2023-01-07 4:55 * <br> Now is history! @@ -38,10 +39,17 @@ public NgVertex<?> handle(NgVertex<?> newResult, Record row) { handle(newResult, node); return newResult; } - + public NgVertex<?> handle(NgVertex<?> newResult, ValueWrapper nodeValueWrapper) { try { - Node node = nodeValueWrapper.asNode(); + return handle(newResult, nodeValueWrapper.asNode()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public NgVertex<?> handle(NgVertex<?> newResult, Node node) { + try { ValueWrapper id = node.getId(); newResult.setVid(ResultSetUtil.getValue(id)); List<String> tags = node.tagNames(); @@ -50,7 +58,7 @@ public NgVertex<?> handle(NgVertex<?> newResult, ValueWrapper nodeValueWrapper) return newResult; } catch (UnsupportedEncodingException e) { throw new ResultHandleException( - String.format("%s : %s", e.getClass().toString(), e.getMessage())); + String.format("%s : %s", e.getClass().toString(), e.getMessage())); } } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java index e98ca27b..5613f6f0 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * A common pojo for paths. @@ -29,9 +30,12 @@ public void setRelationships( public static class Relationship<I> { private I dstID; + private NgVertex<I> dst = new NgVertex<>(); private String edgeName; private Long rank; private I srcID; + private NgVertex<I> src = new NgVertex<>(); + private Map<String,Object> properties; public I getDstID() { return dstID; @@ -64,6 +68,30 @@ public I getSrcID() { public void setSrcID(I srcID) { this.srcID = srcID; } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + public NgVertex<I> getDst() { + return dst; + } + + public void setDst(NgVertex<I> dst) { + this.dst = dst; + } + + public NgVertex<I> getSrc() { + return src; + } + + public void setSrc(NgVertex<I> src) { + this.src = src; + } } } From d9ea3e47cec46a5aa99c8c0de2eb076afd5a5d23 Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Tue, 12 Sep 2023 16:20:52 +0800 Subject: [PATCH 16/56] =?UTF-8?q?=E4=BF=AE=E6=94=B9daobasic=E4=B8=ADshorte?= =?UTF-8?q?stPath=E6=96=B9=E6=B3=95doc=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 45eb10eb..28bc607f 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -450,7 +450,7 @@ default <E> E startNode(Class<E> startType, Class<?> edgeType, I endId) { * Find the shortest path by srcId and dstId. * @param srcId the start node's id * @param dstId the end node's id - * @return Shortest path list. + * @return Shortest path list. entities containing vertext in path. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. */ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I dstId) { MethodModel methodModel = getMethodModel(); From 52771aa5d1845c6d58a71a34286842792b3bf5c9 Mon Sep 17 00:00:00 2001 From: dieyi <admin@zendee.cn> Date: Wed, 13 Sep 2023 09:21:24 +0800 Subject: [PATCH 17/56] =?UTF-8?q?=E7=BB=99=E6=89=A9=E5=B1=95=E5=90=8E?= =?UTF-8?q?=E7=9A=84NgPath=E5=AE=9E=E4=BD=93=E5=A2=9E=E5=8A=A0javadoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 ++++ .../contrib/ngbatis/models/data/NgPath.java | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pom.xml b/pom.xml index e51a77b8..f798dfb7 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,10 @@ <name>soul-gin</name> <email>1533119789@qq.com</email> </developer> + <developer> + <name>dieyi</name> + <email>admin@zendee.cn</email> + </developer> </developers> <properties> diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java index 5613f6f0..ce8821a4 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java @@ -4,6 +4,9 @@ // // This source code is licensed under Apache 2.0 License. +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; + +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -30,11 +33,28 @@ public void setRelationships( public static class Relationship<I> { private I dstID; + /** + * Dest vertex entity. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ private NgVertex<I> dst = new NgVertex<>(); private String edgeName; private Long rank; private I srcID; + + /** + * Source vertex entity. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ private NgVertex<I> src = new NgVertex<>(); + + /** + * Attribute of edge. If you want to obtain attributes in an edge, you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ private Map<String,Object> properties; public I getDstID() { From 37021bf10ef7119ea97435b0d675f005b7315a1d Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Wed, 13 Sep 2023 01:46:38 +0000 Subject: [PATCH 18/56] ci: fix publishing ci close: #227 ref: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md --- .github/workflows/release.yml | 5 ++++- .github/workflows/snapshot.yaml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c365b275..6503e214 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,7 +36,10 @@ jobs: java-version: '8' distribution: 'temurin' gpg-private-key: ${{ secrets.GPG_SECRET }} - gpg-passphrase: ${{ secrets.GPG_PASSWORD }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN - name: Publish package run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index e09803f5..16d1892f 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -38,7 +38,10 @@ jobs: java-version: '8' distribution: 'temurin' gpg-private-key: ${{ secrets.GPG_SECRET }} - gpg-passphrase: ${{ secrets.GPG_PASSWORD }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_CENTRAL_TOKEN - name: Publish package run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true From 5495c1abf4df94e4b0ec8a517ecb5a61cb00439f Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Wed, 13 Sep 2023 01:48:54 +0000 Subject: [PATCH 19/56] fix MAVEN_PASSWORD --- .github/workflows/release.yml | 2 +- .github/workflows/snapshot.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6503e214..997a84b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,7 +39,7 @@ jobs: gpg-passphrase: MAVEN_GPG_PASSPHRASE server-id: ossrh server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN + server-password: MAVEN_PASSWORD - name: Publish package run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index 16d1892f..e40fb99f 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -41,7 +41,7 @@ jobs: gpg-passphrase: MAVEN_GPG_PASSPHRASE server-id: ossrh server-username: MAVEN_USERNAME - server-password: MAVEN_CENTRAL_TOKEN + server-password: MAVEN_PASSWORD - name: Publish package run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true From adb46460d911094c1b88efa49fe004646d17bf64 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Wed, 13 Sep 2023 02:59:38 +0000 Subject: [PATCH 20/56] ci: not setting up pages in doc dryrun - dryrun only happened in pr before merge - removed the wrong step, this will wipe the pages ref: 1. opened: A new pull request is created. 2. synchronize: The pull request's branch is updated with new commits. 3. reopened: A closed pull request is reopened. --- .github/workflows/doc_en_pull_request_dryrun.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/doc_en_pull_request_dryrun.yaml b/.github/workflows/doc_en_pull_request_dryrun.yaml index e14c955f..901ddd1d 100644 --- a/.github/workflows/doc_en_pull_request_dryrun.yaml +++ b/.github/workflows/doc_en_pull_request_dryrun.yaml @@ -2,8 +2,8 @@ name: Dry run Docs Build in PR on: - pull_request: + types: [opened, synchronize, reopened] branches: [master] paths: - 'docs/**' @@ -48,10 +48,8 @@ jobs: node-version: 18 cache: npm cache-dependency-path: ngbatis-docs/package-lock.json - - - name: Setup Pages - uses: actions/configure-pages@v3 - - name: Build with VitePress + + - name: Dryrun Build with VitePress run: | cd ngbatis-docs npm ci From a4c6a997c0f47b92bcc47b2d6cca3898bbd98d73 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Thu, 28 Sep 2023 15:57:37 +0800 Subject: [PATCH 21/56] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- googl_codestyle.xml => google_codestyle.xml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename googl_codestyle.xml => google_codestyle.xml (100%) diff --git a/googl_codestyle.xml b/google_codestyle.xml similarity index 100% rename from googl_codestyle.xml rename to google_codestyle.xml From bfed2c3279a35b42b50bb3a9089f8a52f3947e05 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Fri, 29 Sep 2023 16:21:14 +0800 Subject: [PATCH 22/56] Create .nojekyll to skip the "pages build and deployment" action that wipe the pages --- docs/.nojekyll | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/.nojekyll diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ + From 6f9588f14fdabf5178dd4e5ca39132b7741cf502 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 2 Oct 2023 15:38:33 +0800 Subject: [PATCH 23/56] test: add test space create script and instruction --- ngbatis-demo/src/main/resources/application.yml | 4 +++- ngbatis-demo/src/main/resources/testgraph.ngql | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 ngbatis-demo/src/main/resources/testgraph.ngql diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index 9780fd9c..b9bc8b89 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -12,9 +12,11 @@ nebula: # space name needs to be informed through annotations(@Space) or xml(space="test") # default false(false: Session pool map will not be initialized) use-session-pool: false - hosts: 127.0.0.1:19669 + hosts: 127.0.0.1:9669 username: root password: nebula + # create test space according to resources/testgraph.ngql script + # Specific steps refer to https://github.com/vesoft-inc/nebula-console space: test pool-config: min-conns-size: 0 diff --git a/ngbatis-demo/src/main/resources/testgraph.ngql b/ngbatis-demo/src/main/resources/testgraph.ngql new file mode 100644 index 00000000..a0d6c7ed --- /dev/null +++ b/ngbatis-demo/src/main/resources/testgraph.ngql @@ -0,0 +1,7 @@ +create space if not exists test (vid_type = fixed_string(32)) +:sleep 20 +use test +create tag if not exists person(name string,gender string,height double,age int32 ,birthday datetime) +create tag if not exists employee(name string,gender string,height double,age int32 ,birthday datetime,position string) +create edge if not exists like(likeness double) +create tag index person_index_1 on person(age,birthday) \ No newline at end of file From b9a74b27dc6d5cfc929dca257f49de563353700e Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 2 Oct 2023 15:43:13 +0800 Subject: [PATCH 24/56] test: add test space create script and instruction --- ngbatis-demo/src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index b9bc8b89..440733c7 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -12,7 +12,7 @@ nebula: # space name needs to be informed through annotations(@Space) or xml(space="test") # default false(false: Session pool map will not be initialized) use-session-pool: false - hosts: 127.0.0.1:9669 + hosts: 127.0.0.1:19669 username: root password: nebula # create test space according to resources/testgraph.ngql script From 24b4f4a4b6971c14931ab62b3d443908dce77f08 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 2 Oct 2023 19:21:22 +0800 Subject: [PATCH 25/56] test: add docker-compose.yaml to deploy and test automation --- .../src/main/resources/application.yml | 2 - .../src/main/resources/docker-compose.yaml | 377 ++++++++++++++++++ 2 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 ngbatis-demo/src/main/resources/docker-compose.yaml diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index 440733c7..9780fd9c 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -15,8 +15,6 @@ nebula: hosts: 127.0.0.1:19669 username: root password: nebula - # create test space according to resources/testgraph.ngql script - # Specific steps refer to https://github.com/vesoft-inc/nebula-console space: test pool-config: min-conns-size: 0 diff --git a/ngbatis-demo/src/main/resources/docker-compose.yaml b/ngbatis-demo/src/main/resources/docker-compose.yaml new file mode 100644 index 00000000..687270a8 --- /dev/null +++ b/ngbatis-demo/src/main/resources/docker-compose.yaml @@ -0,0 +1,377 @@ +version: '3.4' +services: + metad0: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.1 + - --ws_ip=172.28.1.1 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.1:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9559:9559" + - 19559 + - 11002 + volumes: + - ./data/meta0:/data/meta:Z + - ./logs/meta0:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + metad1: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.2 + - --ws_ip=172.28.1.2 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.2:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9560:9559" + - 19559 + - 11002 + volumes: + - ./data/meta1:/data/meta:Z + - ./logs/meta1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + metad2: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.3 + - --ws_ip=172.28.1.3 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.3:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9561:9559" + - 19559 + - 11002 + volumes: + - ./data/meta2:/data/meta:Z + - ./logs/meta2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.3 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged0: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.1 + - --ws_ip=172.28.2.1 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.1:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9779:9779" + - 19669 + - 12002 + volumes: + - ./data/storage0:/data/storage:Z + - ./logs/storage0:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged1: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.2 + - --ws_ip=172.28.2.2 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.2:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9780:9779" + - 19669 + - 12002 + volumes: + - ./data/storage1:/data/storage:Z + - ./logs/storage1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged2: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.3 + - --ws_ip=172.28.2.3 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.3:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9781:9779" + - 19669 + - 12002 + volumes: + - ./data/storage2:/data/storage:Z + - ./logs/storage2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.3 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd0: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.1 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.1:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9669:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph0:/logs:Z +# - ./testgraph.ngql:/data/testgraph.ngql +# - type: bind +# source: ./testgraph.ngql +# target: /data/testgraph.ngql + networks: + nebula-net: + ipv4_address: 172.28.3.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd1: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.2 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.2:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9670:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.3.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd2: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.3 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.3:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9671:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.3.3 + restart: on-failure + cap_add: + - SYS_PTRACE + console: + image: vesoft/nebula-console:nightly + entrypoint: "" + command: + - sh + - -c + - | + sleep 3 && + nebula-console -addr graphd0 -port 9669 -u root -p nebula -f /data/testgraph.ngql && + nebula-console -addr graphd0 -port 9669 -u root -p nebula -e 'ADD HOSTS "172.28.2.1":9779,"172.28.2.2":9779,"172.28.2.3":9779' && + sleep 36000 + volumes: + - ./testgraph.ngql:/data/testgraph.ngql + depends_on: + - graphd0 + networks: + - nebula-net + +networks: + nebula-net: + ipam: + driver: default + config: + - subnet: 172.28.0.0/16 From d10eaa428c5be9f0b2df0c6b2e2d02c9cf6f6ef2 Mon Sep 17 00:00:00 2001 From: jerry <jerry@gmail.com> Date: Sat, 7 Oct 2023 19:54:05 +0800 Subject: [PATCH 26/56] fix:class 'ResultSetUtil.java' parse datetime type error #240 --- .../contrib/ngbatis/utils/ResultSetUtil.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java b/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java index 715211ae..5d91c9ed 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java +++ b/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java @@ -9,6 +9,7 @@ import static org.nebula.contrib.ngbatis.utils.ReflectUtil.isCurrentTypeOrParentType; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.schemaByEntityType; +import com.vesoft.nebula.DateTime; import com.vesoft.nebula.ErrorCode; import com.vesoft.nebula.client.graph.data.DateTimeWrapper; import com.vesoft.nebula.client.graph.data.DateWrapper; @@ -126,27 +127,28 @@ public static <T> T getValue(ValueWrapper valueWrapper, Class<T> resultType) { } private static Object transformDateTime(DateTimeWrapper dateTime) { + DateTime localDateTime = dateTime.getLocalDateTime(); try { CALENDAR_CONSTRUCTOR.setAccessible(true); GregorianCalendar calendar = CALENDAR_CONSTRUCTOR.newInstance( - dateTime.getYear(), - dateTime.getMonth() - 1, - dateTime.getDay(), - dateTime.getHour(), - dateTime.getMinute(), - dateTime.getSecond(), - Math.floorDiv(dateTime.getMicrosec(), 1000) + localDateTime.getYear(), + localDateTime.getMonth() - 1, + localDateTime.getDay(), + localDateTime.getHour(), + localDateTime.getMinute(), + localDateTime.getSec(), + Math.floorDiv(localDateTime.getMicrosec(), 1000) ); CALENDAR_CONSTRUCTOR.setAccessible(false); return calendar.getTime(); } catch (Exception e) { return new GregorianCalendar( - dateTime.getYear(), - dateTime.getMonth() - 1, - dateTime.getDay(), - dateTime.getHour(), - dateTime.getMinute(), - dateTime.getSecond() + localDateTime.getYear(), + localDateTime.getMonth() - 1, + localDateTime.getDay(), + localDateTime.getHour(), + localDateTime.getMinute(), + localDateTime.getSec() ).getTime(); } } From 581185f96688d5267478a724d87312fc83e062a5 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Tue, 10 Oct 2023 11:08:33 +0800 Subject: [PATCH 27/56] feat: add insertEdgeBatch interface, define the NgTriplet for the use of triplet --- .../weicheng/ngbatis/demo/pojo/NgTriplet.java | 60 ++ .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 14 +- src/main/resources/NebulaDaoBasic.xml | 738 +++++++++--------- 3 files changed, 449 insertions(+), 363 deletions(-) create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java new file mode 100644 index 00000000..328a31ef --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java @@ -0,0 +1,60 @@ +package ye.weicheng.ngbatis.demo.pojo; + +/** + * @author: SunHB + * @createTime: 2023/10/10 上午12:41 + * @description: + */ +public class NgTriplet<I> { + private I srcId; + private I dstId; + private Object startNode; + private Object edge; + private Object endNode; + + public NgTriplet(Object startNode, Object edge, Object endNode) { + this.startNode = startNode; + this.edge = edge; + this.endNode = endNode; + } + + public I getSrcId() { + return srcId; + } + + public void setSrcId(I srcId) { + this.srcId = srcId; + } + + public I getDstId() { + return dstId; + } + + public void setDstId(I dstId) { + this.dstId = dstId; + } + + public Object getStartNode() { + return startNode; + } + + public void setStartNode(Object startNode) { + this.startNode = startNode; + } + + public Object getEdge() { + return edge; + } + + public void setEdge(Object edge) { + this.edge = edge; + } + + public Object getEndNode() { + return endNode; + } + + public void setEndNode(Object endNode) { + this.endNode = endNode; + } +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 28bc607f..8334869b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -332,7 +332,19 @@ default void insertEdge(@NotNull Object v1, @NotNull Object e, @NotNull Object v ClassModel classModel = getClassModel(this.getClass()); MapperProxy.invoke(classModel, methodModel, v1, e, v2); } - + /** + * @Author sunhb + * @Description 根据三元组列表的头结点,尾节点和尾节点进行插入 + * @Date 2023/10/10 上午11:03 + * @Param + * @param triplets 三元组列表 + * @return void + **/ + default void insertEdgeBatch(List triplets){ + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, triplets); + } /** * 根据三元组值, 插入关系 * <p>Selective: 仅处理非空字段</p> diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 0cf144e8..e0a25a33 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -1,363 +1,377 @@ -<!-- - Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved. - - This source code is licensed under Apache 2.0 License. ---> -<!DOCTYPE mapper SYSTEM "https://nebula-contrib.github.io/ngbatis/ngbatis-mapper.dtd" > -<mapper namespace="org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic"> - - <!--region query zoom--> - <select id="selectById"> - match (n) where id(n) == ${ ng.valueFmt( id ) } return n - </select> - - <select id="selectByIds"> - match (n: `${ ng.tagName( ng_args[0], ng_cm ) }`) - where id(n) in [ ${ ng.join( @ids, ", ", "ng.valueFmt" ) } ] - return n - </select> - - <select id="selectBySelective"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var id = ng.id( ng_args[0], true, false ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } - @} - @} - RETURN n - LIMIT 4000 - </select> - - <select id="selectBySelectiveStringLike"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var id = ng.id( ng_args[0], true, false ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } ${ - ng.ifStringLike( - @kv.values.get( colLP.dataIndex ), - @kv.types.get( colLP.dataIndex ), - @kv.valueNames.get( colLP.dataIndex ) - ) - } - @} - @} - RETURN n - LIMIT 4000 - </select> - - <select id="selectIdBySelective"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var id = ng.id( ng_args[0], true, false ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } - @} - @} - RETURN id(n) - LIMIT 4000 - </select> - - <select id="selectIdBySelectiveStringLike"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var id = ng.id( ng_args[0], true, false ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n)' + ng.ifStringLike( id )) : '' } - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } ${ - ng.ifStringLike( - @kv.values.get( colLP.dataIndex ), - @kv.types.get( colLP.dataIndex ), - @kv.valueNames.get( colLP.dataIndex ) - ) - } - @} - @} - RETURN id(n) - LIMIT 4000 - </select> - - <select id="selectByMap"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var tagName = ng.tagName( ng_args[0], ng_cm ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.dataIndex ) } - @} - @} - RETURN n - LIMIT 4000 - </select> - - <select id="countByMap"> - @var kv = ng.kv( ng_args[0], '', true, true, false ); - @var tagName = ng.tagName( ng_args[0], ng_cm ); - MATCH (n:`${ tagName }`) - WHERE 1 == 1 - @if ( isNotEmpty( @kv.columns ) ) { - @for ( col in @kv.columns ) { - and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.dataIndex ) } - @} - @} - RETURN count(n) - </select> - - <select id="selectPage"> - @var query = @ng_args[0].getEntity(); - @var kv = ng.kv( query, 'entity', false, true, false ); - @var tag = ng.tagName( query, ng_cm ); - MATCH (n:${ tag }) - @if ( isNotEmpty( @kv.columns ) ) { - WHERE - @for ( col in @kv.columns ) { - n.`${ tag }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } ${ !colLP.last ? 'and' : '' } - @} - @} - RETURN n skip $startRow limit $pageSize - </select> - - <select id="countPage"> - @var query = @ng_args[0].getEntity(); - @var kv = ng.kv( query, 'entity', false, true, false ); - @var tag = ng.tagName( query, ng_cm ); - MATCH (n:${ tag }) - @if ( isNotEmpty( @kv.columns ) ) { - WHERE - @for ( col in @kv.columns ) { - n.`${ tag }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } ${ !colLP.last ? 'and' : '' } - @} - @} - RETURN count(n) - </select> - <!--endregion--> - - <!--region insert zoom--> - <insert id="insert"> - @var kv = ng.kv( ng_args[0] ); - @var id = ng.id( ng_args[0] ); - INSERT VERTEX IF NOT EXISTS - @for ( entry in @kv.multiTagColumns ) { - `${ entry.key }` ( - ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } - ) ${ entryLP.last ? '' : ','} - @} - VALUES ${ id } : ( - ${ ng.join( @kv.values ) } - ); - </insert> - - <insert id="insertSelective"> - @var kv = ng.kv( ng_args[0], '', true, true ); - @var id = ng.id( ng_args[0] ); - INSERT VERTEX IF NOT EXISTS - @for ( entry in @kv.multiTagColumns ) { - `${ entry.key }` ( - ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } - ) ${ entryLP.last ? '' : ','} - @} - VALUES ${ id } : ( - ${ ng.join( @kv.values ) } - ); - </insert> - - <insert id="insertBatch"> - @for ( row in ng_args[0] ) { - @var kv = ng.kv( row ); - @var id = ng.id( row ); - @if (rowLP.first) { - INSERT VERTEX IF NOT EXISTS - @for ( entry in @kv.multiTagColumns ) { - `${ entry.key }` ( - ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } - ) ${ entryLP.last ? '' : ','} - @} - VALUES - @} - ${ id } : ( ${ ng.join( @kv.values ) } ) ${ rowLP.last ? '' : ', ' } - @} - </insert> - <!--endregion--> - - <!--region update zoom --> - <update id="updateById"> - @var kv = ng.kv( ng_args[0] ); - @var id = ng.id( ng_args[0] ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - @var fields = ng.fieldNames( ng_args[0] ); - @for ( entry in @kv.multiTagColumns ) { - UPDATE VERTEX ON `${ entry.key }` ${ id } - SET - @for (col in entry.value ) { - @var vIdx = @kv.columns.indexOf( col ); - @var val = @kv.values.get(@vIdx); - `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} - @} - ; - @} - </update> - - <update id="updateByIdSelective"> - @var kv = ng.kv( ng_args[0], '', true, true ); - @var id = ng.id( ng_args[0] ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - @var fields = ng.fieldNames( ng_args[0] ); - @for ( entry in @kv.multiTagColumns ) { - UPDATE VERTEX ON `${ entry.key }` ${ id } - SET - @for (col in entry.value ) { - @var vIdx = @kv.columns.indexOf( col ); - @var val = @kv.values.get(@vIdx); - `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} - @} - ; - @} - </update> - - <update id="updateByIdBatchSelective"> - @for ( row in ng_args[0] ) { - @var kv = ng.kv( row, '', true, true ); - @var id = ng.id( row ); - @var pkName = ng.pkName( row ); - @var tagName = ng.tagName( row ); - - @for ( entry in @kv.multiTagColumns ) { - UPDATE VERTEX ON `${ entry.key }` ${ id } - SET - @for (col in entry.value ) { - @var vIdx = @kv.columns.indexOf( col ); - @var val = @kv.values.get(@vIdx); - `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} - @} - ; - @} - @} - </update> - - <update id="upsertByIdSelective"> - @var kv = ng.kv( ng_args[0], '', true, true ); - @var id = ng.id( ng_args[0] ); - @var pkName = ng.pkName( ng_args[0] ); - @var tagName = ng.tagName( ng_args[0] ); - @var fields = ng.fieldNames( ng_args[0] ); - - @for ( entry in @kv.multiTagColumns ) { - UPSERT VERTEX ON `${ entry.key }` ${ id } - SET - @for (col in entry.value ) { - @var vIdx = @kv.columns.indexOf( col ); - @var val = @kv.values.get(@vIdx); - `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} - @} - ; - @} - </update> - <!--endregion--> - - <!--region delete zoom--> - <delete id="deleteLogicById"> - </delete> - - <delete id="deleteWithEdgeById"> - DELETE VERTEX ${ ng.valueFmt( p0 ) } WITH EDGE - </delete> - - <delete id="deleteById"> - DELETE VERTEX ${ ng.valueFmt( p0 ) } - </delete> - <!--endregion--> - - <!--region graph special--> - <insert id="insertEdge"> - @var kv = ng.kv( ng_args[1], '', null, null, false ); - @var vId1 = ng.id( ng_args[0] ); - @var rank = ng.id( ng_args[1], false ); - @var vId2 = ng.id( ng_args[2] ); - @var e = ng.tagName( ng_args[1] ); - INSERT EDGE `${ e }` ( - ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } - ) - VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( - ${ ng.join( @kv.values ) } - ); - </insert> - - <insert id="insertEdgeSelective"> - @var kv = ng.kv( ng_args[1], '', null, true, false ); - @var vId1 = ng.id( ng_args[0] ); - @var rank = ng.id( ng_args[1], false ); - @var vId2 = ng.id( ng_args[2] ); - @var e = ng.tagName( ng_args[1] ); - - INSERT EDGE `${ e }` ( - ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } - ) - VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( - ${ ng.join( @kv.values ) } - ); - </insert> - - <insert id="upsertEdgeSelective"> - @var kv = ng.kv( ng_args[1], '', null, true, false ); - @var rank = ng.id( ng_args[1] ); - @var tagName = ng.tagName( ng_args[1] ); - @var vId1 = ng.id( ng_args[0] ); - @var vId2 = ng.id( ng_args[2] ); - - UPSERT EDGE ON `${ tagName }` - ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } - @if ( isNotEmpty( @kv.columns ) ) { - SET - @for ( col in @kv.columns ) { - @var val = @kv.values.get(colLP.dataIndex); - `${ col }` = ${ val } ${ colLP.last ? '' : ',' } - @} - @} - </insert> - - <select id="existsEdge"> - MATCH (n)-[r: ${ p1 }]-(n2) - WHERE id(n) == $p0 AND id(n2) == $p2 - RETURN count(*) > 0 - </select> - - <select id="listStartNodes"> - MATCH (n: `${ p0 }`)-[r: `${ p1 }`]->(n2) - WHERE id(n2) == $p2 - RETURN n - </select> - - <select id="startNode"> - MATCH (n: `${ p0 }`)-[r: `${ p1 }`]->(n2) - WHERE id(n2) == $p2 - RETURN n - LIMIT 1 - </select> - - <select id="shortestPath" resultType="org.nebula.contrib.ngbatis.models.data.NgPath"> - @var srcId = ng.valueFmt( srcId ); - @var dstId = ng.valueFmt( dstId ); - FIND SHORTEST PATH FROM ${ srcId } TO ${ dstId } OVER * YIELD path AS p - </select> - <!--endregion--> - +<!-- + Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<!DOCTYPE mapper SYSTEM "https://nebula-contrib.github.io/ngbatis/ngbatis-mapper.dtd" > +<mapper namespace="org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic"> + + <!--region query zoom--> + <select id="selectById"> + match (n) where id(n) == ${ ng.valueFmt( id ) } return n + </select> + + <select id="selectByIds"> + match (n: `${ ng.tagName( ng_args[0], ng_cm ) }`) + where id(n) in [ ${ ng.join( @ids, ", ", "ng.valueFmt" ) } ] + return n + </select> + + <select id="selectBySelective"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var id = ng.id( ng_args[0], true, false ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } + @} + @} + RETURN n + LIMIT 4000 + </select> + + <select id="selectBySelectiveStringLike"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var id = ng.id( ng_args[0], true, false ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } ${ + ng.ifStringLike( + @kv.values.get( colLP.dataIndex ), + @kv.types.get( colLP.dataIndex ), + @kv.valueNames.get( colLP.dataIndex ) + ) + } + @} + @} + RETURN n + LIMIT 4000 + </select> + + <select id="selectIdBySelective"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var id = ng.id( ng_args[0], true, false ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n) == $' + pkName) : '' } + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } + @} + @} + RETURN id(n) + LIMIT 4000 + </select> + + <select id="selectIdBySelectiveStringLike"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var id = ng.id( ng_args[0], true, false ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 ${ isNotEmpty( id ) ? ('\n and id(n)' + ng.ifStringLike( id )) : '' } + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } ${ + ng.ifStringLike( + @kv.values.get( colLP.dataIndex ), + @kv.types.get( colLP.dataIndex ), + @kv.valueNames.get( colLP.dataIndex ) + ) + } + @} + @} + RETURN id(n) + LIMIT 4000 + </select> + + <select id="selectByMap"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var tagName = ng.tagName( ng_args[0], ng_cm ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.dataIndex ) } + @} + @} + RETURN n + LIMIT 4000 + </select> + + <select id="countByMap"> + @var kv = ng.kv( ng_args[0], '', true, true, false ); + @var tagName = ng.tagName( ng_args[0], ng_cm ); + MATCH (n:`${ tagName }`) + WHERE 1 == 1 + @if ( isNotEmpty( @kv.columns ) ) { + @for ( col in @kv.columns ) { + and n.`${ tagName }`.${ col } == $${ @kv.valueNames.get( colLP.dataIndex ) } + @} + @} + RETURN count(n) + </select> + + <select id="selectPage"> + @var query = @ng_args[0].getEntity(); + @var kv = ng.kv( query, 'entity', false, true, false ); + @var tag = ng.tagName( query, ng_cm ); + MATCH (n:${ tag }) + @if ( isNotEmpty( @kv.columns ) ) { + WHERE + @for ( col in @kv.columns ) { + n.`${ tag }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } ${ !colLP.last ? 'and' : '' } + @} + @} + RETURN n skip $startRow limit $pageSize + </select> + + <select id="countPage"> + @var query = @ng_args[0].getEntity(); + @var kv = ng.kv( query, 'entity', false, true, false ); + @var tag = ng.tagName( query, ng_cm ); + MATCH (n:${ tag }) + @if ( isNotEmpty( @kv.columns ) ) { + WHERE + @for ( col in @kv.columns ) { + n.`${ tag }`.${ col } == $${ @kv.valueNames.get( colLP.index - 1 ) } ${ !colLP.last ? 'and' : '' } + @} + @} + RETURN count(n) + </select> + <!--endregion--> + + <!--region insert zoom--> + <insert id="insert"> + @var kv = ng.kv( ng_args[0] ); + @var id = ng.id( ng_args[0] ); + INSERT VERTEX IF NOT EXISTS + @for ( entry in @kv.multiTagColumns ) { + `${ entry.key }` ( + ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } + ) ${ entryLP.last ? '' : ','} + @} + VALUES ${ id } : ( + ${ ng.join( @kv.values ) } + ); + </insert> + + <insert id="insertSelective"> + @var kv = ng.kv( ng_args[0], '', true, true ); + @var id = ng.id( ng_args[0] ); + INSERT VERTEX IF NOT EXISTS + @for ( entry in @kv.multiTagColumns ) { + `${ entry.key }` ( + ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } + ) ${ entryLP.last ? '' : ','} + @} + VALUES ${ id } : ( + ${ ng.join( @kv.values ) } + ); + </insert> + + <insert id="insertBatch"> + @for ( row in ng_args[0] ) { + @var kv = ng.kv( row ); + @var id = ng.id( row ); + @if (rowLP.first) { + INSERT VERTEX IF NOT EXISTS + @for ( entry in @kv.multiTagColumns ) { + `${ entry.key }` ( + ${ ng.join( entry.value, ", ", "ng.schemaFmt" ) } + ) ${ entryLP.last ? '' : ','} + @} + VALUES + @} + ${ id } : ( ${ ng.join( @kv.values ) } ) ${ rowLP.last ? '' : ', ' } + @} + </insert> + <!--endregion--> + + <!--region update zoom --> + <update id="updateById"> + @var kv = ng.kv( ng_args[0] ); + @var id = ng.id( ng_args[0] ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + @var fields = ng.fieldNames( ng_args[0] ); + @for ( entry in @kv.multiTagColumns ) { + UPDATE VERTEX ON `${ entry.key }` ${ id } + SET + @for (col in entry.value ) { + @var vIdx = @kv.columns.indexOf( col ); + @var val = @kv.values.get(@vIdx); + `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} + @} + ; + @} + </update> + + <update id="updateByIdSelective"> + @var kv = ng.kv( ng_args[0], '', true, true ); + @var id = ng.id( ng_args[0] ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + @var fields = ng.fieldNames( ng_args[0] ); + @for ( entry in @kv.multiTagColumns ) { + UPDATE VERTEX ON `${ entry.key }` ${ id } + SET + @for (col in entry.value ) { + @var vIdx = @kv.columns.indexOf( col ); + @var val = @kv.values.get(@vIdx); + `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} + @} + ; + @} + </update> + + <update id="updateByIdBatchSelective"> + @for ( row in ng_args[0] ) { + @var kv = ng.kv( row, '', true, true ); + @var id = ng.id( row ); + @var pkName = ng.pkName( row ); + @var tagName = ng.tagName( row ); + + @for ( entry in @kv.multiTagColumns ) { + UPDATE VERTEX ON `${ entry.key }` ${ id } + SET + @for (col in entry.value ) { + @var vIdx = @kv.columns.indexOf( col ); + @var val = @kv.values.get(@vIdx); + `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} + @} + ; + @} + @} + </update> + + <update id="upsertByIdSelective"> + @var kv = ng.kv( ng_args[0], '', true, true ); + @var id = ng.id( ng_args[0] ); + @var pkName = ng.pkName( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + @var fields = ng.fieldNames( ng_args[0] ); + + @for ( entry in @kv.multiTagColumns ) { + UPSERT VERTEX ON `${ entry.key }` ${ id } + SET + @for (col in entry.value ) { + @var vIdx = @kv.columns.indexOf( col ); + @var val = @kv.values.get(@vIdx); + `${ col }` = ${ nvl(val, "null") } ${ colLP.last ? '' : ','} + @} + ; + @} + </update> + <!--endregion--> + + <!--region delete zoom--> + <delete id="deleteLogicById"> + </delete> + + <delete id="deleteWithEdgeById"> + DELETE VERTEX ${ ng.valueFmt( p0 ) } WITH EDGE + </delete> + + <delete id="deleteById"> + DELETE VERTEX ${ ng.valueFmt( p0 ) } + </delete> + <!--endregion--> + + <!--region graph special--> + <insert id="insertEdge"> + @var kv = ng.kv( ng_args[1], '', null, null, false ); + @var vId1 = ng.id( ng_args[0] ); + @var rank = ng.id( ng_args[1], false ); + @var vId2 = ng.id( ng_args[2] ); + @var e = ng.tagName( ng_args[1] ); + INSERT EDGE `${ e }` ( + ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } + ) + VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( + ${ ng.join( @kv.values ) } + ); + </insert> + + <insert id="insertEdgeSelective"> + @var kv = ng.kv( ng_args[1], '', null, true, false ); + @var vId1 = ng.id( ng_args[0] ); + @var rank = ng.id( ng_args[1], false ); + @var vId2 = ng.id( ng_args[2] ); + @var e = ng.tagName( ng_args[1] ); + + INSERT EDGE `${ e }` ( + ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } + ) + VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( + ${ ng.join( @kv.values ) } + ); + </insert> + <insert id="insertEdgeBatch"> + @for ( row in ng_args[0] ) { + @var kv = ng.kv( row.edge, '', null, null, false ); + @var vId1 = ng.id( row.startNode); + @var rank = ng.id( row.edge, false ); + @var vId2 = ng.id( row.endNode ); + @var e = ng.tagName( row.edge ); + INSERT EDGE `${ e }` ( + ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } + ) + VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( + ${ ng.join( @kv.values ) } + ); + @} + </insert> + <insert id="upsertEdgeSelective"> + @var kv = ng.kv( ng_args[1], '', null, true, false ); + @var rank = ng.id( ng_args[1] ); + @var tagName = ng.tagName( ng_args[1] ); + @var vId1 = ng.id( ng_args[0] ); + @var vId2 = ng.id( ng_args[2] ); + + UPSERT EDGE ON `${ tagName }` + ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } + @if ( isNotEmpty( @kv.columns ) ) { + SET + @for ( col in @kv.columns ) { + @var val = @kv.values.get(colLP.dataIndex); + `${ col }` = ${ val } ${ colLP.last ? '' : ',' } + @} + @} + </insert> + + <select id="existsEdge"> + MATCH (n)-[r: ${ p1 }]-(n2) + WHERE id(n) == $p0 AND id(n2) == $p2 + RETURN count(*) > 0 + </select> + + <select id="listStartNodes"> + MATCH (n: `${ p0 }`)-[r: `${ p1 }`]->(n2) + WHERE id(n2) == $p2 + RETURN n + </select> + + <select id="startNode"> + MATCH (n: `${ p0 }`)-[r: `${ p1 }`]->(n2) + WHERE id(n2) == $p2 + RETURN n + LIMIT 1 + </select> + + <select id="shortestPath" resultType="org.nebula.contrib.ngbatis.models.data.NgPath"> + @var srcId = ng.valueFmt( srcId ); + @var dstId = ng.valueFmt( dstId ); + FIND SHORTEST PATH FROM ${ srcId } TO ${ dstId } OVER * YIELD path AS p + </select> + <!--endregion--> + </mapper> \ No newline at end of file From 05ffeab65ca1cfbee5e3b95843d35292f71e6995 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Tue, 10 Oct 2023 11:55:02 +0800 Subject: [PATCH 28/56] test: add test module --- .../ngbatis/demo/NebulaBasicDaoTests.java | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 101e904a..60f1258d 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -16,12 +16,14 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.locationtech.jts.util.Assert; +import org.nebula.contrib.ngbatis.models.data.NgEdge; import org.nebula.contrib.ngbatis.models.data.NgPath; import org.nebula.contrib.ngbatis.utils.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ye.weicheng.ngbatis.demo.pojo.Like; import ye.weicheng.ngbatis.demo.pojo.LikeWithRank; +import ye.weicheng.ngbatis.demo.pojo.NgTriplet; import ye.weicheng.ngbatis.demo.pojo.Person; import ye.weicheng.ngbatis.demo.repository.TestRepository; @@ -60,7 +62,7 @@ public void selectBySelective() { List<Person> people = repository.selectBySelective(person); System.out.println(JSON.toJSONString(people)); } - + @Test public void selectBySelectiveWithBigDecimal() { Person person = new Person(); @@ -68,7 +70,7 @@ public void selectBySelectiveWithBigDecimal() { List<Person> people = repository.selectBySelective(person); System.out.println(JSON.toJSONString(people)); } - + /** * https://github.com/nebula-contrib/ngbatis/issues/35. */ @@ -107,7 +109,7 @@ public void selectIdBySelectiveStringLike() { List<String> people = repository.selectIdBySelectiveStringLike(person); System.out.println(people); } - + @Test public void selectByMap() { Map<String, Object> query = new HashMap<>(); @@ -182,7 +184,7 @@ public void insertSelectiveWithBigDecimal() { @Test public void insertBatch() { long now = System.currentTimeMillis(); - + Person person1 = new Person(); person1.setName("IB" + now); person1.setGender("M"); @@ -192,7 +194,7 @@ public void insertBatch() { person2.setName("IB" + (now + 1)); person2.setAge(18); person2.setBirthday(new Date()); - + Person person3 = new Person(); person3.setName("IB" + (now + 2)); person3.setGender("M"); @@ -202,7 +204,7 @@ public void insertBatch() { people.add(person1); people.add(person2);; people.add(person3); - + repository.insertBatch(people); } // endregion @@ -215,14 +217,14 @@ public void updateById() { Person person = new Person(); person.setName(name); repository.insert(person); - + Integer newAge = randomAge(); person.setAge(newAge); person.setGender("F"); repository.updateById(person); - + Person personDb = repository.selectById(name); - + Assert.isTrue(newAge.equals(personDb.getAge())); } @@ -276,17 +278,17 @@ public void updateByIdBatch() { Integer newAge2 = randomAge(); person2.setAge(newAge2); - + Integer newAge3 = randomAge(); person3.setAge(newAge3); - + repository.updateByIdBatchSelective(people); - + List<String> ids = people.stream().map(Person::getName).collect(Collectors.toList()); List<Person> peopleDb = repository.selectByIds(ids); Assert.isTrue(peopleDb.size() == 3); - + for (Person personDb : peopleDb) { for (Person person : people) { if (Objects.equals(personDb.getName(), person.getName())) { @@ -384,7 +386,7 @@ public void insertEdgeUseNodeId() { like.setLikeness(0.202210171102); repository.insertEdge("吴小极", like, "刘小洲"); } - + @Test public void insertEdgeUseNodeId2() { LikeWithRank like = new LikeWithRank(); @@ -424,7 +426,25 @@ public void insertEdgeSelective() { repository.insertEdgeSelective(person1, likeWithRank, person2); } + @Test + public void insertEdgeBatch(){ + List<NgTriplet> ngTripletList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Person person1 = new Person(); + person1.setName("p1_"+i); + repository.insertSelective(person1); + Person person2 = new Person(); + person2.setName("p2_"+i); + repository.insertSelective(person2); + + Like like = new Like(); + like.setLikeness(0.87); + + ngTripletList.add(new NgTriplet(person1,like,person2)); + } + repository.insertEdgeBatch(ngTripletList); + } @Test public void upsertEdgeSelective() { Person person1 = new Person(); @@ -460,7 +480,7 @@ public void startNode() { Person whoIsStartForTest = repository.startNode(Like.class, "易小海"); System.out.println(JSON.toJSONString(whoIsStartForTest)); } - + @Test public void shortestPath() { List<NgPath<String>> ngPaths = repository.shortestPath("吴小极", "刘小洲"); From 202481fa555d56d390851dfe42135092cc6d42f1 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Fri, 13 Oct 2023 20:41:23 +0800 Subject: [PATCH 29/56] move NgTriplet.java file position to main project --- .../ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java | 7 +++---- .../nebula/contrib/ngbatis/models/data}/NgTriplet.java | 8 ++------ 2 files changed, 5 insertions(+), 10 deletions(-) rename {ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo => src/main/java/org/nebula/contrib/ngbatis/models/data}/NgTriplet.java (89%) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 60f1258d..7cb6de83 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -16,14 +16,13 @@ import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.locationtech.jts.util.Assert; -import org.nebula.contrib.ngbatis.models.data.NgEdge; import org.nebula.contrib.ngbatis.models.data.NgPath; import org.nebula.contrib.ngbatis.utils.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ye.weicheng.ngbatis.demo.pojo.Like; import ye.weicheng.ngbatis.demo.pojo.LikeWithRank; -import ye.weicheng.ngbatis.demo.pojo.NgTriplet; +import org.nebula.contrib.ngbatis.models.data.NgTriplet; import ye.weicheng.ngbatis.demo.pojo.Person; import ye.weicheng.ngbatis.demo.repository.TestRepository; @@ -202,7 +201,7 @@ public void insertBatch() { List<Person> people = new ArrayList<>(); people.add(person1); - people.add(person2);; + people.add(person2); people.add(person3); repository.insertBatch(people); @@ -268,7 +267,7 @@ public void updateByIdBatch() { List<Person> people = new ArrayList<>(); people.add(person1); - people.add(person2);; + people.add(person2); people.add(person3); repository.insertBatch(people); diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java similarity index 89% rename from ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java rename to src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java index 328a31ef..8c2203a4 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NgTriplet.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java @@ -1,10 +1,6 @@ -package ye.weicheng.ngbatis.demo.pojo; +package org.nebula.contrib.ngbatis.models.data; + -/** - * @author: SunHB - * @createTime: 2023/10/10 上午12:41 - * @description: - */ public class NgTriplet<I> { private I srcId; private I dstId; From fde597678f302cee0af6b0fd0ce8e1cae027ea80 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Sat, 14 Oct 2023 13:54:43 +0800 Subject: [PATCH 30/56] edit the codestyle according to nebula_java_style_checks.xml --- .../ngbatis/demo/NebulaBasicDaoTests.java | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 7cb6de83..29c1faef 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -17,12 +17,12 @@ import org.junit.jupiter.api.Test; import org.locationtech.jts.util.Assert; import org.nebula.contrib.ngbatis.models.data.NgPath; +import org.nebula.contrib.ngbatis.models.data.NgTriplet; import org.nebula.contrib.ngbatis.utils.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ye.weicheng.ngbatis.demo.pojo.Like; import ye.weicheng.ngbatis.demo.pojo.LikeWithRank; -import org.nebula.contrib.ngbatis.models.data.NgTriplet; import ye.weicheng.ngbatis.demo.pojo.Person; import ye.weicheng.ngbatis.demo.repository.TestRepository; @@ -425,25 +425,27 @@ public void insertEdgeSelective() { repository.insertEdgeSelective(person1, likeWithRank, person2); } + @Test - public void insertEdgeBatch(){ - List<NgTriplet> ngTripletList = new ArrayList<>(); - for (int i = 0; i < 3; i++) { - Person person1 = new Person(); - person1.setName("p1_"+i); - repository.insertSelective(person1); + public void insertEdgeBatch() { + List<NgTriplet<String>> ngTripletList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Person person1 = new Person(); + person1.setName("p1_" + i); + repository.insertSelective(person1); - Person person2 = new Person(); - person2.setName("p2_"+i); - repository.insertSelective(person2); + Person person2 = new Person(); + person2.setName("p2_" + i); + repository.insertSelective(person2); - Like like = new Like(); - like.setLikeness(0.87); + Like like = new Like(); + like.setLikeness(0.87); - ngTripletList.add(new NgTriplet(person1,like,person2)); - } - repository.insertEdgeBatch(ngTripletList); + ngTripletList.add(new NgTriplet<>(person1,like,person2)); + } + repository.insertEdgeBatch(ngTripletList); } + @Test public void upsertEdgeSelective() { Person person1 = new Person(); From b27d4e20dd59080b56551457b6441a1882a9318a Mon Sep 17 00:00:00 2001 From: Sunhb <57407733+shbone@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:11:37 +0800 Subject: [PATCH 31/56] feat: add deleteByIdBatch interface (#2) --- .../ngbatis/demo/NebulaBasicDaoTests.java | 25 +++++++++++++++++ pom.xml | 4 +++ .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 28 +++++++++++++++---- src/main/resources/NebulaDaoBasic.xml | 6 +++- 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 29c1faef..fc061eeb 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -331,6 +331,31 @@ public void deleteById() { int row = repository.deleteById("赵小洋"); System.out.println(row); } + + @Test + public void deleteByIdBatch() { + long now = System.currentTimeMillis(); + Person person1 = new Person(); + person1.setName("UBB" + now); + + Person person2 = new Person(); + person2.setName("UBB" + (now + 1)); + + Person person3 = new Person(); + person3.setName("UBB" + (now + 2)); + + List<Person> people = new ArrayList<>(); + people.add(person1); + people.add(person2); + people.add(person3); + repository.insertBatch(people); + + List<String> peopleIds = new ArrayList<>(); + peopleIds.add(person1.getName()); + peopleIds.add(person2.getName()); + peopleIds.add(person3.getName()); + Assert.equals(repository.deleteByIdBatch(peopleIds),1); + } // endregion // region graph special diff --git a/pom.xml b/pom.xml index f798dfb7..914607bb 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,10 @@ <name>dieyi</name> <email>admin@zendee.cn</email> </developer> + <developer> + <name>shbone</name> + <email>598924626@qq.com</email> + </developer> </developers> <properties> diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 8334869b..85fe9cae 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -314,7 +314,22 @@ default int deleteById(I id) { ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); return resultSet.isSucceeded() ? 1 : 0; } + // endregion + /** + * <p>通过 主键批量删除当前记录</p> + * + * @param ids 表记录主键列表 + * @return 是否删除成功,成功 1,失败 0 + */ + default int deleteByIdBatch(List<I> ids) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, ids); + return resultSet.isSucceeded() ? 1 : 0; + } // region graph special /** @@ -332,19 +347,18 @@ default void insertEdge(@NotNull Object v1, @NotNull Object e, @NotNull Object v ClassModel classModel = getClassModel(this.getClass()); MapperProxy.invoke(classModel, methodModel, v1, e, v2); } + /** * @Author sunhb * @Description 根据三元组列表的头结点,尾节点和尾节点进行插入 * @Date 2023/10/10 上午11:03 - * @Param - * @param triplets 三元组列表 - * @return void **/ - default void insertEdgeBatch(List triplets){ + default void insertEdgeBatch(List triplets) { MethodModel methodModel = getMethodModel(); ClassModel classModel = getClassModel(this.getClass()); MapperProxy.invoke(classModel, methodModel, triplets); } + /** * 根据三元组值, 插入关系 * <p>Selective: 仅处理非空字段</p> @@ -462,7 +476,9 @@ default <E> E startNode(Class<E> startType, Class<?> edgeType, I endId) { * Find the shortest path by srcId and dstId. * @param srcId the start node's id * @param dstId the end node's id - * @return Shortest path list. entities containing vertext in path. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. + * @return Shortest path list. entities containing vertext in path. + * If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. */ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I dstId) { MethodModel methodModel = getMethodModel(); @@ -471,6 +487,8 @@ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I ClassModel classModel = getClassModel(this.getClass()); return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); } + + // endregion } diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index e0a25a33..540068fc 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -285,7 +285,11 @@ DELETE VERTEX ${ ng.valueFmt( p0 ) } </delete> <!--endregion--> - + <delete id="deleteByIdBatch"> + @for ( v in ng_args[0] ) { + DELETE VERTEX ${ ng.valueFmt( v )}; + @} + </delete> <!--region graph special--> <insert id="insertEdge"> @var kv = ng.kv( ng_args[1], '', null, null, false ); From 9cdbe9c6634dfe788c5a1d2c99d989d18fe31bd8 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 16 Oct 2023 11:15:35 +0800 Subject: [PATCH 32/56] feat: add deleteByIdBatch interface and my information --- .../ngbatis/demo/NebulaBasicDaoTests.java | 25 + pom.xml | 4 + .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 952 +++++++++--------- src/main/resources/NebulaDaoBasic.xml | 7 + 4 files changed, 521 insertions(+), 467 deletions(-) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 101e904a..cfe68273 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -332,6 +332,31 @@ public void deleteById() { } // endregion + @Test + public void deleteByIdBatch() { + long now = System.currentTimeMillis(); + Person person1 = new Person(); + person1.setName("UBB" + now); + + Person person2 = new Person(); + person2.setName("UBB" + (now + 1)); + + Person person3 = new Person(); + person3.setName("UBB" + (now + 2)); + + List<Person> people = new ArrayList<>(); + people.add(person1); + people.add(person2); + people.add(person3); + repository.insertBatch(people); + + List<String> peopleIds = new ArrayList<>(); + peopleIds.add(person1.getName()); + peopleIds.add(person2.getName()); + peopleIds.add(person3.getName()); + Assert.equals(repository.deleteByIdBatch(peopleIds),1); + } + // region graph special @Test public void insertEdge() { diff --git a/pom.xml b/pom.xml index f798dfb7..914607bb 100644 --- a/pom.xml +++ b/pom.xml @@ -32,6 +32,10 @@ <name>dieyi</name> <email>admin@zendee.cn</email> </developer> + <developer> + <name>shbone</name> + <email>598924626@qq.com</email> + </developer> </developers> <properties> diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 28bc607f..3a3d4f3b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -1,467 +1,485 @@ -package org.nebula.contrib.ngbatis.proxy; - -// Copyright (c) 2022 All project authors. All rights reserved. -// -// This source code is licensed under Apache 2.0 License. - -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.edgeName; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.entityType; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getClassModel; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getCqlTpl; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getMethodModel; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.pkType; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.proxy; -import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.vertexName; - -import com.sun.istack.NotNull; -import com.vesoft.nebula.client.graph.data.ResultSet; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import org.nebula.contrib.ngbatis.exception.QueryException; -import org.nebula.contrib.ngbatis.models.ClassModel; -import org.nebula.contrib.ngbatis.models.MethodModel; -import org.nebula.contrib.ngbatis.models.data.NgPath; -import org.nebula.contrib.ngbatis.utils.Page; -import org.springframework.data.repository.query.Param; - -/** - * 数据访问的基类,用于提供单表 CRUD 与基本的节点关系操作<br> - * <strong>以下在方法注释中所说的“对应类型” 均指的是 泛 型T</strong> - * - * @author yeweicheng - * @since 2022-06-12 12:21 - * <br>Now is history! - */ -public interface NebulaDaoBasic<T, I extends Serializable> { - - // region query zoom - /** - * <p>通过主键查询对应表的单条记录</p> - * - * @param id 记录主键 - * @return 表中的记录对应的实体对象 - */ - default T selectById(@Param("id") I id) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - return (T) MapperProxy.invoke(classModel, methodModel, id); - } - - /** - * <p>通过多个 id 值查询符合条件的记录</p> - * - * @param ids 多个 id - * @return 多个 id 对应的节点 - */ - default List<T> selectByIds(@Param("ids") Collection<I> ids) { - MethodModel methodModel = getMethodModel(); - Class<?> currentType = this.getClass(); - Class<?> entityType = entityType(currentType); - methodModel.setResultType(entityType); - ClassModel classModel = getClassModel(this.getClass()); - return (List<T>) MapperProxy.invoke(classModel, methodModel, ids); - } - - /** - * <p>以实体类为载体,存放查询条件,不为空的属性为查询条件</p> - * - * @param record 单个节点做为查询条件 - * @return 符合条件节点的集合 - */ - default List<T> selectBySelective(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List<T>) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - * <p>以实体类为载体,存放查询条件,不为空的属性为查询条件,String 类型的属性使用模糊查询</p> - * - * @param record 查询条件 - * @return 符合条件的节点集合 - */ - default List<T> selectBySelectiveStringLike(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List<T>) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - * <p>按条件查出所有符合条件的记录的 主键 </p> - * - * @param record 查询条件 - * @return 符合查询条件的节点 id - */ - default List<I> selectIdBySelective(T record) { - MethodModel methodModel = getMethodModel(); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(pkType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List<I>) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - * <p>按条件查出所有符合条件的记录的 主键 (String字段模糊查询)</p> - * - * @param record 查询条件 - * @return 符合查询条件的节点 id - */ - default List<I> selectIdBySelectiveStringLike(T record) { - MethodModel methodModel = getMethodModel(); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(pkType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List<I>) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - * <p>通过 map 存放查询参数,查询多条记录并映射成实体类</p> - * - * @param param 查询条件 - * @return 符合查询条件的节点集合 - */ - default List<T> selectByMap(Map<String, Object> param) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List<T>) MapperProxy.invoke(classModel, methodModel, param); - } - - /** - * <p>统计符合条件的记录数</p> - * - * @param param 查询条件 - * @return 统及符合查询条件的总节点数 - */ - default Long countByMap(Map<String, Object> param) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - return (Long) MapperProxy.invoke(classModel, methodModel, param); - } - - /** - * 查询对应类型的数据并分页 - * - * @param page 分页的参数,与分页结果的容器 - * @return 分页的结果 - */ - default List<T> selectPage(Page<T> page) { - MethodModel methodModel = getMethodModel(); - Long total = countPage(page); - page.setTotal(total); - if (total == 0) { - return Collections.EMPTY_LIST; - } - methodModel.setReturnType(List.class); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - List<T> proxy = (List<T>) MapperProxy.invoke(classModel, methodModel, page); - page.setRows(proxy); - return proxy; - } - - default Long countPage(Page<T> page) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - return (Long) MapperProxy.invoke(classModel, methodModel, page); - } - // endregion - - // region insert zoom - /** - * <p>插入一条记录,全属性插入</p> - * - * @param record 当前表对应的记录数据 - * @return 是否删除成功,成功 1,失败 0 - */ - default Integer insert(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(ResultSet.class); - methodModel.setResultType(ResultSet.class); - ClassModel classModel = getClassModel(this.getClass()); - ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, record); - return resultSet.isSucceeded() ? 1 : 0; - } - - /** - * <p>插入非空字段。</p> - * - * @param record 单个顶点 - * @return 是否删除成功,成功 1,失败 0 - */ - default Integer insertSelective(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(ResultSet.class); - methodModel.setResultType(ResultSet.class); - ClassModel classModel = getClassModel(this.getClass()); - ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, record); - return resultSet.isSucceeded() ? 1 : 0; - } - - /** - * 批量插入全字段 - * @param ts 当前Tag下的多节点 - */ - default void insertBatch(List<T> ts) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, ts); - } - // endregion - - // region update zoom - default T updateById(T record) { - MethodModel methodModel = getMethodModel(); - Class<?> entityType = record.getClass(); - methodModel.setReturnType(entityType); - methodModel.setResultType(entityType); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, record); - return record; - } - - /** - * <p>更新</p> - * - * @param record 节点 - * @return 原参数对象 - */ - default T updateByIdSelective(T record) { - MethodModel methodModel = getMethodModel(); - Class<?> entityType = record.getClass(); - methodModel.setReturnType(entityType); - methodModel.setResultType(entityType); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, record); - return record; - } - - /** - * 批量更新行记录,selective - * @param ts 当前Tag下的多节点 - */ - default void updateByIdBatchSelective(List<T> ts) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, ts); - } - - /** - * <p>新增/更新</p> - * <p>Selective: 仅处理非空字段</p> - * - * @param record 节点 - */ - default void upsertByIdSelective(T record) { - MethodModel methodModel = getMethodModel(); - Class<?> entityType = record.getClass(); - methodModel.setReturnType(entityType); - methodModel.setResultType(entityType); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, record); - } - // endregion - - // region delete zoom - /** - * <p>数据操作,逻辑删除接口,前提当前类 有字段 is_del </p> - * - * @param id 表记录主键 - * @return 是否执行成功,成功 1 ,失败 0 - */ - default int deleteLogicById(I id) { - throw new QueryException("No implements"); - } - - /** - * <p>数据操作,根据节点 id 将节点连同其连接的关系一同物理删除</p> - * - * @param id 表记录主键 - * @return 是否执行成功,成功 1 ,失败 0 - */ - default int deleteWithEdgeById(I id) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(ResultSet.class); - methodModel.setResultType(ResultSet.class); - ClassModel classModel = getClassModel(this.getClass()); - ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); - return resultSet.isSucceeded() ? 1 : 0; - } - - /** - * <p>通过 主键删除当前记录</p> - * - * @param id 表记录主键 - * @return 是否删除成功,成功 1,失败 0 - */ - default int deleteById(I id) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(ResultSet.class); - methodModel.setResultType(ResultSet.class); - ClassModel classModel = getClassModel(this.getClass()); - ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); - return resultSet.isSucceeded() ? 1 : 0; - } - // endregion - - // region graph special - /** - * 根据三元组值,插入关系 - * - * @param v1 开始节点值 或 开始节点id - * @param e 关系值 - * @param v2 结束节点值 或 结束节点id - */ - default void insertEdge(@NotNull Object v1, @NotNull Object e, @NotNull Object v2) { - if (v2 == null || v1 == null || e == null) { - return; - } - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, v1, e, v2); - } - - /** - * 根据三元组值, 插入关系 - * <p>Selective: 仅处理非空字段</p> - * - * @param src 开始节点值 - * @param edge 关系值 - * @param dst 结束节点值 - */ - default void insertEdgeSelective(@NotNull Object src, @NotNull Object edge, @NotNull Object dst) { - if (dst == null || src == null || edge == null) { - return; - } - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, src, edge, dst); - } - - /** - * 根据三元组值, 插入关系 - * <p>Selective: 仅处理非空字段</p> - * - * @param src 开始节点值 - * @param edge 关系值 - * @param dst 结束节点值 - */ - default void upsertEdgeSelective(@NotNull Object src, @NotNull Object edge, @NotNull Object dst) { - if (dst == null || src == null || edge == null) { - return; - } - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, src, edge, dst); - } - - /** - * 提供开始节点的id、结束节点的id 与 关系名,判断是否已经建立关系 - * - * @param startId 开始节点的 id - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @return 数据库中,两个 id 的节点是否有关系 - */ - default Boolean existsEdge(I startId, Class<?> edgeType, I endId) { - String cqlTpl = getCqlTpl(); - String edgeName = edgeName(edgeType); - return (Boolean) proxy(this.getClass(), Boolean.class, cqlTpl, - new Class[]{Serializable.class, Class.class, Serializable.class}, startId, edgeName, - endId); - } - - /** - * 通过结束节点id与关系类型获取所有开始节点,<br> 开始节点类型为当前接口实现类所管理的实体对应的类型 - * - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @return 开始节点 - */ - default List<T> listStartNodes(Class<?> edgeType, I endId) { - Class<?> startType = entityType(this.getClass()); - return (List<T>) listStartNodes(startType, edgeType, endId); - } - - /** - * 指定开始节点类型,并通过结束节点id与关系类型获取所有开始节点 - * - * @param startType 开始节点的类型 - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @return 开始节点 - */ - default List<?> listStartNodes(Class<?> startType, Class<?> edgeType, I endId) { - String cqlTpl = getCqlTpl(); - String startVertexName = vertexName(startType); - String edgeName = edgeName(edgeType); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - Class<?> returnType = entityType(daoType); - return (List<?>) proxy(daoType, returnType, cqlTpl, - new Class[]{Class.class, Class.class, Serializable.class}, startVertexName, edgeName, - endId); - } - - /** - * 通过结束节点id与关系类型获取第一个开始节点,<br> 开始节点类型为当前接口实现类所管理的实体对应的类型 (对应类型) - * - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @return 开始节点 - */ - default T startNode(Class<?> edgeType, I endId) { - Class<?> startType = entityType(this.getClass()); - return (T) startNode(startType, edgeType, endId); - } - - /** - * 指定开始节点类型,并通过结束节点id与关系类型获取第一个开始节点 - * - * @param startType 开始节点的类型 - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @param <E> 开始节点的类型 - * @return 开始节点 - */ - default <E> E startNode(Class<E> startType, Class<?> edgeType, I endId) { - String cqlTpl = getCqlTpl(); - String startVertexName = vertexName(startType); - String edgeName = edgeName(edgeType); - Class<? extends NebulaDaoBasic> daoType = this.getClass(); - Class<?> returnType = entityType(daoType); - return (E) proxy(daoType, returnType, cqlTpl, - new Class[]{Class.class, Class.class, Serializable.class}, startVertexName, edgeName, - endId); - } - - /** - * Find the shortest path by srcId and dstId. - * @param srcId the start node's id - * @param dstId the end node's id - * @return Shortest path list. entities containing vertext in path. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. - */ - default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I dstId) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(Collection.class); - methodModel.setResultType(NgPath.class); - ClassModel classModel = getClassModel(this.getClass()); - return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); - } - // endregion - -} - - - +package org.nebula.contrib.ngbatis.proxy; + +// Copyright (c) 2022 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.edgeName; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.entityType; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getClassModel; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getCqlTpl; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.getMethodModel; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.pkType; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.proxy; +import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.vertexName; + +import com.sun.istack.NotNull; +import com.vesoft.nebula.client.graph.data.ResultSet; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.nebula.contrib.ngbatis.exception.QueryException; +import org.nebula.contrib.ngbatis.models.ClassModel; +import org.nebula.contrib.ngbatis.models.MethodModel; +import org.nebula.contrib.ngbatis.models.data.NgPath; +import org.nebula.contrib.ngbatis.utils.Page; +import org.springframework.data.repository.query.Param; + +/** + * 数据访问的基类,用于提供单表 CRUD 与基本的节点关系操作<br> + * <strong>以下在方法注释中所说的“对应类型” 均指的是 泛 型T</strong> + * + * @author yeweicheng + * @since 2022-06-12 12:21 + * <br>Now is history! + */ +public interface NebulaDaoBasic<T, I extends Serializable> { + + // region query zoom + /** + * <p>通过主键查询对应表的单条记录</p> + * + * @param id 记录主键 + * @return 表中的记录对应的实体对象 + */ + default T selectById(@Param("id") I id) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + return (T) MapperProxy.invoke(classModel, methodModel, id); + } + + /** + * <p>通过多个 id 值查询符合条件的记录</p> + * + * @param ids 多个 id + * @return 多个 id 对应的节点 + */ + default List<T> selectByIds(@Param("ids") Collection<I> ids) { + MethodModel methodModel = getMethodModel(); + Class<?> currentType = this.getClass(); + Class<?> entityType = entityType(currentType); + methodModel.setResultType(entityType); + ClassModel classModel = getClassModel(this.getClass()); + return (List<T>) MapperProxy.invoke(classModel, methodModel, ids); + } + + /** + * <p>以实体类为载体,存放查询条件,不为空的属性为查询条件</p> + * + * @param record 单个节点做为查询条件 + * @return 符合条件节点的集合 + */ + default List<T> selectBySelective(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List<T>) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + * <p>以实体类为载体,存放查询条件,不为空的属性为查询条件,String 类型的属性使用模糊查询</p> + * + * @param record 查询条件 + * @return 符合条件的节点集合 + */ + default List<T> selectBySelectiveStringLike(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List<T>) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + * <p>按条件查出所有符合条件的记录的 主键 </p> + * + * @param record 查询条件 + * @return 符合查询条件的节点 id + */ + default List<I> selectIdBySelective(T record) { + MethodModel methodModel = getMethodModel(); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(pkType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List<I>) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + * <p>按条件查出所有符合条件的记录的 主键 (String字段模糊查询)</p> + * + * @param record 查询条件 + * @return 符合查询条件的节点 id + */ + default List<I> selectIdBySelectiveStringLike(T record) { + MethodModel methodModel = getMethodModel(); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(pkType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List<I>) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + * <p>通过 map 存放查询参数,查询多条记录并映射成实体类</p> + * + * @param param 查询条件 + * @return 符合查询条件的节点集合 + */ + default List<T> selectByMap(Map<String, Object> param) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List<T>) MapperProxy.invoke(classModel, methodModel, param); + } + + /** + * <p>统计符合条件的记录数</p> + * + * @param param 查询条件 + * @return 统及符合查询条件的总节点数 + */ + default Long countByMap(Map<String, Object> param) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + return (Long) MapperProxy.invoke(classModel, methodModel, param); + } + + /** + * 查询对应类型的数据并分页 + * + * @param page 分页的参数,与分页结果的容器 + * @return 分页的结果 + */ + default List<T> selectPage(Page<T> page) { + MethodModel methodModel = getMethodModel(); + Long total = countPage(page); + page.setTotal(total); + if (total == 0) { + return Collections.EMPTY_LIST; + } + methodModel.setReturnType(List.class); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + List<T> proxy = (List<T>) MapperProxy.invoke(classModel, methodModel, page); + page.setRows(proxy); + return proxy; + } + + default Long countPage(Page<T> page) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + return (Long) MapperProxy.invoke(classModel, methodModel, page); + } + // endregion + + // region insert zoom + /** + * <p>插入一条记录,全属性插入</p> + * + * @param record 当前表对应的记录数据 + * @return 是否删除成功,成功 1,失败 0 + */ + default Integer insert(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, record); + return resultSet.isSucceeded() ? 1 : 0; + } + + /** + * <p>插入非空字段。</p> + * + * @param record 单个顶点 + * @return 是否删除成功,成功 1,失败 0 + */ + default Integer insertSelective(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, record); + return resultSet.isSucceeded() ? 1 : 0; + } + + /** + * 批量插入全字段 + * @param ts 当前Tag下的多节点 + */ + default void insertBatch(List<T> ts) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, ts); + } + // endregion + + // region update zoom + default T updateById(T record) { + MethodModel methodModel = getMethodModel(); + Class<?> entityType = record.getClass(); + methodModel.setReturnType(entityType); + methodModel.setResultType(entityType); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, record); + return record; + } + + /** + * <p>更新</p> + * + * @param record 节点 + * @return 原参数对象 + */ + default T updateByIdSelective(T record) { + MethodModel methodModel = getMethodModel(); + Class<?> entityType = record.getClass(); + methodModel.setReturnType(entityType); + methodModel.setResultType(entityType); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, record); + return record; + } + + /** + * 批量更新行记录,selective + * @param ts 当前Tag下的多节点 + */ + default void updateByIdBatchSelective(List<T> ts) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, ts); + } + + /** + * <p>新增/更新</p> + * <p>Selective: 仅处理非空字段</p> + * + * @param record 节点 + */ + default void upsertByIdSelective(T record) { + MethodModel methodModel = getMethodModel(); + Class<?> entityType = record.getClass(); + methodModel.setReturnType(entityType); + methodModel.setResultType(entityType); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, record); + } + // endregion + + // region delete zoom + /** + * <p>数据操作,逻辑删除接口,前提当前类 有字段 is_del </p> + * + * @param id 表记录主键 + * @return 是否执行成功,成功 1 ,失败 0 + */ + default int deleteLogicById(I id) { + throw new QueryException("No implements"); + } + + /** + * <p>数据操作,根据节点 id 将节点连同其连接的关系一同物理删除</p> + * + * @param id 表记录主键 + * @return 是否执行成功,成功 1 ,失败 0 + */ + default int deleteWithEdgeById(I id) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); + return resultSet.isSucceeded() ? 1 : 0; + } + + /** + * <p>通过 主键删除当前记录</p> + * + * @param id 表记录主键 + * @return 是否删除成功,成功 1,失败 0 + */ + default int deleteById(I id) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); + return resultSet.isSucceeded() ? 1 : 0; + } + + + /** + * <p>通过 主键批量删除当前记录</p> + * + * @param ids 表记录主键列表 + * @return 是否删除成功,成功 1,失败 0 + */ + default int deleteByIdBatch(List<I> ids) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, ids); + return resultSet.isSucceeded() ? 1 : 0; + } + // endregion + + // region graph special + /** + * 根据三元组值,插入关系 + * + * @param v1 开始节点值 或 开始节点id + * @param e 关系值 + * @param v2 结束节点值 或 结束节点id + */ + default void insertEdge(@NotNull Object v1, @NotNull Object e, @NotNull Object v2) { + if (v2 == null || v1 == null || e == null) { + return; + } + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, v1, e, v2); + } + + /** + * 根据三元组值, 插入关系 + * <p>Selective: 仅处理非空字段</p> + * + * @param src 开始节点值 + * @param edge 关系值 + * @param dst 结束节点值 + */ + default void insertEdgeSelective(@NotNull Object src, @NotNull Object edge, @NotNull Object dst) { + if (dst == null || src == null || edge == null) { + return; + } + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, src, edge, dst); + } + + /** + * 根据三元组值, 插入关系 + * <p>Selective: 仅处理非空字段</p> + * + * @param src 开始节点值 + * @param edge 关系值 + * @param dst 结束节点值 + */ + default void upsertEdgeSelective(@NotNull Object src, @NotNull Object edge, @NotNull Object dst) { + if (dst == null || src == null || edge == null) { + return; + } + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, src, edge, dst); + } + + /** + * 提供开始节点的id、结束节点的id 与 关系名,判断是否已经建立关系 + * + * @param startId 开始节点的 id + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @return 数据库中,两个 id 的节点是否有关系 + */ + default Boolean existsEdge(I startId, Class<?> edgeType, I endId) { + String cqlTpl = getCqlTpl(); + String edgeName = edgeName(edgeType); + return (Boolean) proxy(this.getClass(), Boolean.class, cqlTpl, + new Class[]{Serializable.class, Class.class, Serializable.class}, startId, edgeName, + endId); + } + + /** + * 通过结束节点id与关系类型获取所有开始节点,<br> 开始节点类型为当前接口实现类所管理的实体对应的类型 + * + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @return 开始节点 + */ + default List<T> listStartNodes(Class<?> edgeType, I endId) { + Class<?> startType = entityType(this.getClass()); + return (List<T>) listStartNodes(startType, edgeType, endId); + } + + /** + * 指定开始节点类型,并通过结束节点id与关系类型获取所有开始节点 + * + * @param startType 开始节点的类型 + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @return 开始节点 + */ + default List<?> listStartNodes(Class<?> startType, Class<?> edgeType, I endId) { + String cqlTpl = getCqlTpl(); + String startVertexName = vertexName(startType); + String edgeName = edgeName(edgeType); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + Class<?> returnType = entityType(daoType); + return (List<?>) proxy(daoType, returnType, cqlTpl, + new Class[]{Class.class, Class.class, Serializable.class}, startVertexName, edgeName, + endId); + } + + /** + * 通过结束节点id与关系类型获取第一个开始节点,<br> 开始节点类型为当前接口实现类所管理的实体对应的类型 (对应类型) + * + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @return 开始节点 + */ + default T startNode(Class<?> edgeType, I endId) { + Class<?> startType = entityType(this.getClass()); + return (T) startNode(startType, edgeType, endId); + } + + /** + * 指定开始节点类型,并通过结束节点id与关系类型获取第一个开始节点 + * + * @param startType 开始节点的类型 + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @param <E> 开始节点的类型 + * @return 开始节点 + */ + default <E> E startNode(Class<E> startType, Class<?> edgeType, I endId) { + String cqlTpl = getCqlTpl(); + String startVertexName = vertexName(startType); + String edgeName = edgeName(edgeType); + Class<? extends NebulaDaoBasic> daoType = this.getClass(); + Class<?> returnType = entityType(daoType); + return (E) proxy(daoType, returnType, cqlTpl, + new Class[]{Class.class, Class.class, Serializable.class}, startVertexName, edgeName, + endId); + } + + /** + * Find the shortest path by srcId and dstId. + * @param srcId the start node's id + * @param dstId the end node's id + * @return Shortest path list. entities containing vertext in path. + * If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. + */ + default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I dstId) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(Collection.class); + methodModel.setResultType(NgPath.class); + ClassModel classModel = getClassModel(this.getClass()); + return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); + } + // endregion + +} + + + diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 0cf144e8..78bb352a 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -284,6 +284,13 @@ <delete id="deleteById"> DELETE VERTEX ${ ng.valueFmt( p0 ) } </delete> + + + <delete id="deleteByIdBatch"> + @for ( v in ng_args[0] ) { + DELETE VERTEX ${ ng.valueFmt( v )}; + @} + </delete> <!--endregion--> <!--region graph special--> From 2d48962798ff0b50483a4fd5ea7eb0ae395cac97 Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 16 Oct 2023 18:25:58 +0800 Subject: [PATCH 33/56] update change format --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 3a3d4f3b..40690973 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -477,6 +477,8 @@ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I ClassModel classModel = getClassModel(this.getClass()); return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); } + + // endregion } From b1b00a0806a40e12a68ef69be36ba3058beb6f9b Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Mon, 16 Oct 2023 18:27:57 +0800 Subject: [PATCH 34/56] Revert "update change format" This reverts commit 2d48962798ff0b50483a4fd5ea7eb0ae395cac97. --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 40690973..3a3d4f3b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -477,8 +477,6 @@ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I ClassModel classModel = getClassModel(this.getClass()); return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); } - - // endregion } From 91275eddbc1756737a90a79246b33a80ccc5a91c Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Sun, 22 Oct 2023 16:59:29 +0800 Subject: [PATCH 35/56] edit deleteByIdBatch delete method --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- src/main/resources/NebulaDaoBasic.xml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 3a3d4f3b..5a8bb329 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -322,7 +322,7 @@ default int deleteById(I id) { * @param ids 表记录主键列表 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteByIdBatch(List<I> ids) { + default int deleteByIdBatch(@Param("ids") Collection<I> ids) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 78bb352a..4f908839 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -287,9 +287,7 @@ <delete id="deleteByIdBatch"> - @for ( v in ng_args[0] ) { - DELETE VERTEX ${ ng.valueFmt( v )}; - @} + DELETE VERTEX ${ ng.join( @ids, ", ", "ng.valueFmt" ) } </delete> <!--endregion--> From 4c97021a6e4f860c285b8a1c15caa84eb8bac39c Mon Sep 17 00:00:00 2001 From: shbone <598924626@qq.com> Date: Tue, 24 Oct 2023 12:00:37 +0800 Subject: [PATCH 36/56] update deleteByIdBatch delete method --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- src/main/resources/NebulaDaoBasic.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 5a8bb329..5fa09858 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -322,7 +322,7 @@ default int deleteById(I id) { * @param ids 表记录主键列表 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteByIdBatch(@Param("ids") Collection<I> ids) { + default int deleteByIdBatch (Collection<I> ids) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 4f908839..ae8f7aca 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -287,7 +287,7 @@ <delete id="deleteByIdBatch"> - DELETE VERTEX ${ ng.join( @ids, ", ", "ng.valueFmt" ) } + DELETE VERTEX ${ ng.join( p0, ", ", "ng.valueFmt" ) } </delete> <!--endregion--> From b2ee3d2c1a3342ee130fd4b53d432505fc1c5386 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Tue, 24 Oct 2023 12:59:42 +0800 Subject: [PATCH 37/56] fix change loss in rebasing --- .../java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- src/main/resources/NebulaDaoBasic.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 73af8869..4308497d 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -322,7 +322,7 @@ default int deleteById(I id) { * @param ids 表记录主键列表 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteByIdBatch(List<I> ids) { + default int deleteByIdBatch (Collection<I> ids) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index f7403628..97ed1311 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -287,7 +287,7 @@ <delete id="deleteByIdBatch"> - DELETE VERTEX ${ ng.join( p0, ", ", "ng.valueFmt" ) } + DELETE VERTEX ${ ng.join( p0, ", ", "ng.valueFmt" ) } </delete> <!--endregion--> @@ -381,4 +381,4 @@ </select> <!--endregion--> -</mapper> \ No newline at end of file +</mapper> From 5775f048de7d8953d691f50e291d2bc6c936c034 Mon Sep 17 00:00:00 2001 From: Zubeen <zubeenqadry@gmail.com> Date: Thu, 26 Oct 2023 01:01:51 +0530 Subject: [PATCH 38/56] Update operation-sequence.md --- docs/en/md/step-forward-docs/operation-sequence.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index 2a7ede55..ab282589 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -1,4 +1,4 @@ -# Operatior Sequence +# Operation Sequence ## Initialization process at service startup From 069595e5fecf1512e53dc282631ac1688cd451e2 Mon Sep 17 00:00:00 2001 From: Zubeen <zubeenqadry@gmail.com> Date: Thu, 26 Oct 2023 01:22:41 +0530 Subject: [PATCH 39/56] add EXECUTION-PROCESS.md to docs --- .../step-forward-docs/operation-sequence.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index ab282589..8bdba069 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -1,3 +1,77 @@ +<!-- +Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved. + +This source code is licensed under Apache 2.0 License. +--> + +# Detailed Description of the Framework Execution Process + +## Initialization + +1. Scanned by Spring Boot for initialization. The entry point is configured in: [spring.factories](./src/main/resources/META-INF/spring.factories). +2. The starting class is: [NgbatisContextInitialize](src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java). +3. Initialization process: + 1. Read NebulaPoolConfig connection information from the Spring Boot configuration file. + 2. Create a global context: [MapperContext](src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java). + 3. Read and parse templates for NebulaDaoBasic, storing them in the context. Performed by: [DaoResourceLoader](./src/main/java/org/nebula/contrib/ngbatis/io/DaoResourceLoader.java). + 1. Read files specified by cql.parser.mapper-tpl-location. + 2. Use JSoup for XML parsing (method names, nGQL templates). + 4. Read and parse user-created XXXDao.xml files, storing them in the context. Performed by: [MapperResourceLoader](./src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java). + 1. Read all XML files specified by cql.parser.mapper-locations. + 2. Use JSoup to parse each file. + 1. Parse XML files, retrieve corresponding interfaces and create a class model: [ClassModel](./src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java). + 2. Parse subtags, retrieve specific methods, and create a method model: [MethodModel](./src/main/java/org/nebula/contrib/ngbatis/models/MethodModel.java). + 5. Create NebulaPool and store it in the context. + 6. Establish the relationship between explicit entity types and database types (MapperContext.tagTypeMapping). By default, types for the generic T of NebulaDaoBasic are loaded. If NebulaDaoBasic is not used, developers can add their own types. For example, put: key: "person," value: Person.class. + 7. Register XXXDao objects as Spring-managed beans. + 1. Generate dynamic proxy classes using ASM based on class model information. These proxy classes exist in memory as bytecode. Performed by: [MapperProxyClassGenerator](./src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxyClassGenerator.java). + 1. Class bytecode + 2. No-argument constructor bytecode + 3. Method bytecode + > The actual method called is MapperProxy.invoke, passing in class and method information along with runtime parameters. The corresponding nGQL is retrieved from the context. See details below in [Runtime]. + 2. Load the proxy class into the JVM. Performed by: [RAMClassLoader](src/main/java/org/nebula/contrib/ngbatis/proxy/RamClassLoader.java). + 3. Retrieve the fully qualified interface names from the class model and register the classes loaded in step 2 as Spring beans managed by the Spring bean container. + 8. Register result set handlers in bulk. The mechanism involves extending the AbstractResultHandler abstract class. When objects are created, they are registered in the context. This mechanism handles different result types inside ResultSets, corresponding to different return values in nGQL. For more details, see [Runtime]. + +> At this point, the initialization process of ngbatis dynamic proxies is complete. + +## Application Configuration, Main Class [Env](src/main/java/org/nebula/contrib/ngbatis/Env.java) + +1. Declare an nGQL parameter parser. The default approach uses the Beetl template engine for parsing. [BeetlTextRender](./src/main/java/org/nebula/contrib/ngbatis/binding/BeetlTextRender.java). + > You can implement your own [TextResolver](src/main/java/org/nebula/contrib/ngbatis/TextResolver.java) and manage it with @Primary if you want to use a different text resolver. +2. Specify the primary key generator (vertex id and edge rank value setter). You can use a timestamp-based primary key generator to obtain primary keys, but it is recommended to implement your own key generation strategy based on your application's architecture. + + ```java + @Configuration + public class PkGeneratorConfig { + @Bean + public PkGenerator pkGenerator() { + return new TimestampPkGenerator(); + } + } + ``` + +3. You can further customize result handling for various types by extending [AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java). + +## Runtime + +1. Business logic integrates dynamic proxy classes into business classes through dependency injection. +2. Business classes invoke actual methods and pass parameters. +3. Dynamic proxies execute MapperProxy.invoke (interface name, method name, parameter list). + 1. Read interface parameter serializers and serialize interface parameters to match placeholders in XML with key-value pairs. + 2. Replace placeholders in the XML. + 3. Retrieve a session and execute executeWithParameter. + 4. Result handling: Result handlers are routed through [ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver), with the choice determined by the return value declared in the method model and the declared generic resultType. In this step, the ORM process is completed. + +## Developer Usage Approach (for complex extensions, see [Application Configuration] if there are no specific requirements) + +1. Specify a primary key generator as shown in [Application Configuration.2]. +2. Create XXXDao.java. +3. Create XXXDao.xml and specify the namespace as XXXDao.java. +4. Write nGQL in XXXDao.xml. +5. When calling the business logic, inject XXXDao directly and call the corresponding method to retrieve and execute the nGQL without handling the result set, thus obtaining the required entity objects. + + # Operation Sequence ## Initialization process at service startup From 7202a50b619b8a5b05f2f67c55b77023a511ca4e Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Thu, 26 Oct 2023 09:13:06 +0800 Subject: [PATCH 40/56] ci: remove file scope of vitepress it seems github page wiping will still be triggered --- .github/workflows/doc_en.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/doc_en.yaml b/.github/workflows/doc_en.yaml index 17097261..d49e3cef 100644 --- a/.github/workflows/doc_en.yaml +++ b/.github/workflows/doc_en.yaml @@ -5,9 +5,6 @@ on: push: branches: [master] - paths: - - 'docs/**' - - '.github/workflows/**' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From 0cc650f20d2e995fa51312fd656e7c9f478e4ca7 Mon Sep 17 00:00:00 2001 From: Zubeen <zubeenqadry@gmail.com> Date: Fri, 27 Oct 2023 02:29:19 +0530 Subject: [PATCH 41/56] Fix linter issues --- docs/en/md/step-forward-docs/operation-sequence.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index 8bdba069..bde05bdb 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -71,7 +71,6 @@ This source code is licensed under Apache 2.0 License. 4. Write nGQL in XXXDao.xml. 5. When calling the business logic, inject XXXDao directly and call the corresponding method to retrieve and execute the nGQL without handling the result set, thus obtaining the required entity objects. - # Operation Sequence ## Initialization process at service startup From 797695a61db41d853c0bd0fc5385f1ce125f1aac Mon Sep 17 00:00:00 2001 From: Zubeen <zubeenqadry@gmail.com> Date: Sat, 28 Oct 2023 04:21:03 +0530 Subject: [PATCH 42/56] Fix dead link in operation-sequence.md --- docs/en/md/step-forward-docs/operation-sequence.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index bde05bdb..d2847ccf 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -61,7 +61,7 @@ This source code is licensed under Apache 2.0 License. 1. Read interface parameter serializers and serialize interface parameters to match placeholders in XML with key-value pairs. 2. Replace placeholders in the XML. 3. Retrieve a session and execute executeWithParameter. - 4. Result handling: Result handlers are routed through [ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver), with the choice determined by the return value declared in the method model and the declared generic resultType. In this step, the ORM process is completed. + 4. Result handling: Result handlers are routed through [ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver.java), with the choice determined by the return value declared in the method model and the declared generic resultType. In this step, the ORM process is completed. ## Developer Usage Approach (for complex extensions, see [Application Configuration] if there are no specific requirements) From 6f1dab442d1162ca38046fde91539f779b745386 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Fri, 10 Nov 2023 14:25:26 +0800 Subject: [PATCH 43/56] fix: remove duplicate methods in test case. --- .../ngbatis/demo/NebulaBasicDaoTests.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index a307cd82..fc061eeb 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -358,31 +358,6 @@ public void deleteByIdBatch() { } // endregion - @Test - public void deleteByIdBatch() { - long now = System.currentTimeMillis(); - Person person1 = new Person(); - person1.setName("UBB" + now); - - Person person2 = new Person(); - person2.setName("UBB" + (now + 1)); - - Person person3 = new Person(); - person3.setName("UBB" + (now + 2)); - - List<Person> people = new ArrayList<>(); - people.add(person1); - people.add(person2); - people.add(person3); - repository.insertBatch(people); - - List<String> peopleIds = new ArrayList<>(); - peopleIds.add(person1.getName()); - peopleIds.add(person2.getName()); - peopleIds.add(person3.getName()); - Assert.equals(repository.deleteByIdBatch(peopleIds),1); - } - // region graph special @Test public void insertEdge() { From 11bdbf1a49bdc5ab1e77059a90aa25680d811c49 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Fri, 10 Nov 2023 14:52:00 +0800 Subject: [PATCH 44/56] fix: support methods in mapper tags to set space to null. --- CHANGELOG.md | 9 +++++ .../ngbatis/demo/repository/DropSpaceDao.java | 23 ++++++++++++ .../main/resources/mapper/DropSpaceDao.xml | 20 +++++++++++ .../demo/repository/DropSpaceDaoTest.java | 35 +++++++++++++++++++ .../contrib/ngbatis/proxy/MapperProxy.java | 19 ++++++++-- 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java create mode 100644 ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml create mode 100644 ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index b4800300..0411f793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,15 @@ This source code is licensed under Apache 2.0 License. - nebula-java: 3.5.0 -> 3.6.0 ## Bugfix +- fix: support methods in mapper tags to set space to null. + - Such as: + ```xml + <mapper namespace="..."> + <create id="createSpace" space="null"> + create space new_space ( vid_type = INT64 ); + </create> + </mapper> + ``` - fix: [#190](https://github.com/nebula-contrib/ngbatis/issues/190) Insert failed when tag has no attributes - chore: removing and exclude some packages: log4j related or useless. diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java new file mode 100644 index 00000000..b03a4da9 --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java @@ -0,0 +1,23 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2023 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import java.util.List; + +/** + * 方法中指定该语句不使用space,比如说 create space 等语句-DAO + * @author yeweicheng + * @since 2023-11-10 13:18 + * <br>Now is history! + */ +public interface DropSpaceDao { + + void createSpace(String name); + + void dropSpace(String name); + + List<String> showTags(); + +} diff --git a/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml new file mode 100644 index 00000000..d5033969 --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml @@ -0,0 +1,20 @@ +<!-- + Copyright (c) 2023 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.DropSpaceDao" space="test_drop"> + + <delete id="dropSpace"> + drop space ${ p0 }; + </delete> + + <select id="createSpace" space="null"> + create space ${ p0 } ( vid_type = INT64 ); + </select> + + <select id="showTags" resultType="java.lang.String"> + SHOW TAGS; + </select> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java new file mode 100644 index 00000000..a0618792 --- /dev/null +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java @@ -0,0 +1,35 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2023 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * @author yeweicheng + * @since 2023-11-10 13:26 + * <br>Now is history! + */ +@SpringBootTest +class DropSpaceDaoTest { + + @Autowired + private DropSpaceDao dao; + + @Test + void dropSpace() throws InterruptedException { + String spaceName = "test_drop"; + dao.createSpace(spaceName); + Thread.sleep(10 * 1000); + + List<String> tags = dao.showTags(); + System.out.println(tags); + + dao.dropSpace(spaceName); + } + +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java index 182faa51..ed6ea024 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java @@ -5,6 +5,7 @@ // This source code is licensed under Apache 2.0 License. import static org.apache.commons.lang3.ObjectUtils.isEmpty; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.nebula.contrib.ngbatis.models.ClassModel.PROXY_SUFFIX; import com.vesoft.nebula.client.graph.SessionPool; @@ -231,7 +232,7 @@ public static ResultSet executeWithParameter(ClassModel cm, MethodModel mm, Stri autoSwitch = qlAndSpace[0] == null ? "" : qlAndSpace[0]; session = localSession.getSession(); result = session.executeWithParameter(gql, params); - localSession.setCurrentSpace(result.getSpaceName()); + localSession.setCurrentSpace(getSpace(result)); if (result.isSucceeded()) { return result; } else { @@ -339,11 +340,25 @@ private static String[] qlWithSpace(LocalSession localSession, String gql, Strin * @return 目标space */ public static String getSpace(ClassModel cm, MethodModel mm) { - return mm != null && mm.getSpace() != null ? mm.getSpace() + String methodSpace; + return (mm != null && (methodSpace = mm.getSpace()) != null) + ? ( + "null".equals(methodSpace.trim()) ? null : methodSpace + ) : cm != null && cm.getSpace() != null ? cm.getSpace() : ENV.getSpace(); } + /** + * 从结果集中获取当前的 space + * @param result 脚本执行之后的结果集 + * @return 结果集所对应的 space + */ + private static String getSpace(ResultSet result) { + String spaceName = result.getSpaceName(); + return isBlank(spaceName) ? null : spaceName; + } + public static Logger getLog() { return log; } From 985a8de452ed2693d9fad03738773bd45eec0b7b Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Fri, 10 Nov 2023 15:10:57 +0800 Subject: [PATCH 45/56] lint: fix CHANGELOG.md lint --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0411f793..7a911857 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,10 @@ This source code is licensed under Apache 2.0 License. - nebula-java: 3.5.0 -> 3.6.0 ## Bugfix + - fix: support methods in mapper tags to set space to null. - - Such as: + - Such as: + ```xml <mapper namespace="..."> <create id="createSpace" space="null"> From ab3b3ef941a30a5e311434c8fc5e4a4202e7dc21 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Mon, 13 Nov 2023 22:26:14 +0800 Subject: [PATCH 46/56] fix: code style --- .../binding/beetl/functions/IncludeFn.java | 74 ++++++------- .../ngbatis/handler/NgPathResultHandler.java | 10 +- .../handler/NgVertexResultHandler.java | 11 +- .../ngbatis/io/MapperResourceLoader.java | 38 +++---- .../contrib/ngbatis/models/NgqlModel.java | 36 +++---- .../contrib/ngbatis/models/data/NgPath.java | 19 ++-- .../ngbatis/models/data/NgTriplet.java | 102 +++++++++--------- .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- 8 files changed, 148 insertions(+), 144 deletions(-) diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java index 7c19158b..b92de28b 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java @@ -1,51 +1,53 @@ package org.nebula.contrib.ngbatis.binding.beetl.functions; +import java.util.LinkedHashMap; +import java.util.Map; import org.beetl.core.Template; import org.nebula.contrib.ngbatis.models.ClassModel; import org.nebula.contrib.ngbatis.models.MapperContext; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import java.util.LinkedHashMap; -import java.util.Map; - /** * TODO * 2023-9-6 14:28 lyw. */ -public class IncludeFn extends AbstractFunction<String,Map<String,Object>,Void,Void,Void,Void>{ +public class IncludeFn extends + AbstractFunction<String, Map<String, Object>, Void, Void, Void, Void> { - @Override - public Object call(String ngql,Map<String,Object> args) { - if(StringUtils.isEmpty(ngql)){ - throw new RuntimeException("未指定nGQL片段"); - } - int idx = ngql.lastIndexOf("."); - ClassModel classModel; - String ngqlId; - if(idx < 0){ - ngqlId = ngql; - classModel = (ClassModel) ctx.globalVar.get("ng_cm"); - }else{ - String namespace = ngql.substring(0,idx); - ngqlId = ngql.substring(idx + 1); - classModel = MapperContext.newInstance().getInterfaces().get(namespace + ClassModel.PROXY_SUFFIX); - } - if(CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty(classModel.getNgqls().get(ngqlId))){ - throw new RuntimeException("未找到 nGQL(" + ngql + ") 的定义"); - } - Map<String,Object> param; - if(!CollectionUtils.isEmpty(args)){ - //防止同名的 子片段参数 覆盖 父片段参数,导致渲染结果与预期不一致。 - param = new LinkedHashMap<>(ctx.globalVar); - param.putAll(args); - }else{ - param = ctx.globalVar; - } - String text = classModel.getNgqls().get(ngqlId).getText(); - Template template = ctx.gt.getTemplate(text); - template.fastBinding(param); - template.renderTo(ctx.byteWriter); - return null; + @Override + public Object call(String ngql, Map<String, Object> args) { + if (StringUtils.isEmpty(ngql)) { + throw new RuntimeException("未指定nGQL片段"); + } + int idx = ngql.lastIndexOf("."); + ClassModel classModel; + String ngqlId; + if (idx < 0) { + ngqlId = ngql; + classModel = (ClassModel) ctx.globalVar.get("ng_cm"); + } else { + String namespace = ngql.substring(0, idx); + ngqlId = ngql.substring(idx + 1); + classModel = MapperContext.newInstance().getInterfaces() + .get(namespace + ClassModel.PROXY_SUFFIX); + } + if (CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty( + classModel.getNgqls().get(ngqlId))) { + throw new RuntimeException("未找到 nGQL(" + ngql + ") 的定义"); + } + Map<String, Object> param; + if (!CollectionUtils.isEmpty(args)) { + //防止同名的 子片段参数 覆盖 父片段参数,导致渲染结果与预期不一致。 + param = new LinkedHashMap<>(ctx.globalVar); + param.putAll(args); + } else { + param = ctx.globalVar; } + String text = classModel.getNgqls().get(ngqlId).getText(); + Template template = ctx.gt.getTemplate(text); + template.fastBinding(param); + template.renderTo(ctx.byteWriter); + return null; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java index 4d4f495e..1cad862a 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java @@ -7,18 +7,18 @@ import com.vesoft.nebula.client.graph.data.PathWrapper; import com.vesoft.nebula.client.graph.data.ResultSet; import com.vesoft.nebula.client.graph.data.ResultSet.Record; +import java.io.UnsupportedEncodingException; +import javax.annotation.Resource; import org.nebula.contrib.ngbatis.models.data.NgPath; import org.nebula.contrib.ngbatis.utils.ResultSetUtil; import org.springframework.stereotype.Component; -import javax.annotation.Resource; -import java.io.UnsupportedEncodingException; - /** - * Convert the path data from ResultSet to NgPath. + * Convert the path data from ResultSet to NgPath. + * * @author yeweicheng * @since 2023-01-07 4:54 - * <br> Now is history! + * <br> Now is history! */ @Component public class NgPathResultHandler extends AbstractResultHandler<NgPath<?>, NgPath<?>> { diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java index 8cf20c63..0065cb41 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java @@ -4,20 +4,19 @@ // // This source code is licensed under Apache 2.0 License. +import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.nodePropsToMap; + import com.vesoft.nebula.client.graph.data.Node; import com.vesoft.nebula.client.graph.data.ResultSet; import com.vesoft.nebula.client.graph.data.ResultSet.Record; import com.vesoft.nebula.client.graph.data.ValueWrapper; +import java.io.UnsupportedEncodingException; +import java.util.List; import org.nebula.contrib.ngbatis.exception.ResultHandleException; import org.nebula.contrib.ngbatis.models.data.NgVertex; import org.nebula.contrib.ngbatis.utils.ResultSetUtil; import org.springframework.stereotype.Component; -import java.io.UnsupportedEncodingException; -import java.util.List; - -import static org.nebula.contrib.ngbatis.utils.ResultSetUtil.nodePropsToMap; - /** * Convert the vertex data from ResultSet to NgVertex. * @author yeweicheng @@ -58,7 +57,7 @@ public NgVertex<?> handle(NgVertex<?> newResult, Node node) { return newResult; } catch (UnsupportedEncodingException e) { throw new ResultHandleException( - String.format("%s : %s", e.getClass().toString(), e.getMessage())); + String.format("%s : %s", e.getClass().toString(), e.getMessage())); } } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index b8e570d4..06fa3be2 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -17,7 +17,11 @@ import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -163,25 +167,23 @@ private Map<String, MethodModel> parseMethodModel(ClassModel cm, List<Node> node if (methodNode instanceof Element) { - if(((Element) methodNode).tagName().equalsIgnoreCase("nGQL")){ - if(Objects.isNull(cm.getNgqls())){ + if (((Element) methodNode).tagName().equalsIgnoreCase("nGQL")) { + if (Objects.isNull(cm.getNgqls())) { cm.setNgqls(new HashMap<>()); } NgqlModel ngqlModel = parseNgqlModel((Element) methodNode); cm.getNgqls().put(ngqlModel.getId(),ngqlModel); - }else{ + } else { MethodModel methodModel = parseMethodModel(methodNode); addSpaceToSessionPool(methodModel.getSpace()); Method method = getNameUniqueMethod(namespace, methodModel.getId()); methodModel.setMethod(method); Assert.notNull(method, - "接口 " + namespace.getName() + " 中,未声明 xml 中的出现的方法:" + methodModel.getId()); + "接口 " + namespace.getName() + " 中,未声明 xml 中的出现的方法:" + methodModel.getId()); checkReturnType(method, namespace); pageSupport(method, methodModel, methodNames, methods, namespace); methods.put(methodModel.getId(), methodModel); } - - } } return methods; @@ -208,10 +210,10 @@ protected MethodModel parseMethodModel(Node node) { /** * 解析nGQL语句片段 - * @param ngqlEl + * @param ngqlEl xml 中的 <nGQL>标签 * @return */ - protected NgqlModel parseNgqlModel(Element ngqlEl){ + protected NgqlModel parseNgqlModel(Element ngqlEl) { return new NgqlModel(ngqlEl.id(),ngqlEl.text()); } @@ -238,21 +240,21 @@ private void checkReturnType(Method method, Class namespace) { * @param methods 用于将需要分页的接口,自动追加两个接口,用于生成动态代理 */ private void pageSupport(Method method, MethodModel methodModel, List<String> methodNames, - Map<String, MethodModel> methods, Class<?> namespace) throws NoSuchMethodException { + Map<String, MethodModel> methods, Class<?> namespace) throws NoSuchMethodException { Class<?>[] parameterTypes = method.getParameterTypes(); List<Class<?>> parameterTypeList = Arrays.asList(parameterTypes); if (parameterTypeList.contains(Page.class)) { int pageParamIndex = parameterTypeList.indexOf(Page.class); MethodModel pageMethod = - createPageMethod( - methodModel, methodNames, parameterTypes, pageParamIndex, namespace - ); + createPageMethod( + methodModel, methodNames, parameterTypes, pageParamIndex, namespace + ); methods.put(pageMethod.getId(), pageMethod); MethodModel countMethod = createCountMethod( methodModel, methodNames, parameterTypes, namespace ); - + methods.put(countMethod.getId(), countMethod); } } @@ -267,11 +269,11 @@ private void pageSupport(Method method, MethodModel methodModel, List<String> me * @return 自动分页的计数方法 */ private MethodModel createCountMethod(MethodModel methodModel, List<String> methodNames, - Class<?>[] parameterTypes, Class<?> namespace) throws NoSuchMethodException { + Class<?>[] parameterTypes, Class<?> namespace) throws NoSuchMethodException { String methodName = methodModel.getId(); String countMethodName = String.format("%s$Count", methodName); Assert.isTrue(!methodNames.contains(countMethodName), - "There is a method name conflicts with " + countMethodName); + "There is a method name conflicts with " + countMethodName); MethodModel countMethodModel = new MethodModel(); setParamAnnotations(parameterTypes, namespace, methodName, countMethodModel); countMethodModel.setParameterTypes(parameterTypes); @@ -298,12 +300,12 @@ private MethodModel createCountMethod(MethodModel methodModel, List<String> meth * @return 查询范围条目方法 的方法模型 */ private MethodModel createPageMethod(MethodModel methodModel, List<String> methodNames, - Class<?>[] parameterTypes, int pageParamIndex, Class<?> namespace) + Class<?>[] parameterTypes, int pageParamIndex, Class<?> namespace) throws NoSuchMethodException { String methodName = methodModel.getId(); String pageMethodName = String.format("%s$Page", methodName); Assert.isTrue(!methodNames.contains(pageMethodName), - "There is a method name conflicts with " + pageMethodName); + "There is a method name conflicts with " + pageMethodName); MethodModel pageMethodModel = new MethodModel(); Annotation[][] parameterAnnotations = setParamAnnotations(parameterTypes, namespace, methodName, pageMethodModel); diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java index 5e7cf995..1ff455b2 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java @@ -6,28 +6,28 @@ */ public class NgqlModel { - private String id; - private String text; + private String id; + private String text; - public NgqlModel(String id, String text) { - this.id = id; - this.text = text; - } + public NgqlModel(String id, String text) { + this.id = id; + this.text = text; + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getText() { - return text; - } + public String getText() { + return text; + } - public void setText(String text) { - this.text = text; - } + public void setText(String text) { + this.text = text; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java index ce8821a4..c8483314 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java @@ -4,12 +4,10 @@ // // This source code is licensed under Apache 2.0 License. -import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; - -import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; /** * A common pojo for paths. @@ -19,7 +17,7 @@ * <br> Now is history! */ public class NgPath<I> { - + private List<Relationship<I>> relationships = new ArrayList<>(); public List<Relationship<I>> getRelationships() { @@ -27,14 +25,15 @@ public List<Relationship<I>> getRelationships() { } public void setRelationships( - List<Relationship<I>> relationships) { + List<Relationship<I>> relationships) { this.relationships = relationships; } public static class Relationship<I> { private I dstID; /** - * Dest vertex entity. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. + * Dest vertex entity. If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. * <br/> * {@link NebulaDaoBasic#shortestPath} default without prop */ @@ -44,14 +43,16 @@ public static class Relationship<I> { private I srcID; /** - * Source vertex entity. If you want to obtain attributes within an entity, you need to use “with prop” in the nGQL. + * Source vertex entity. If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. * <br/> * {@link NebulaDaoBasic#shortestPath} default without prop */ private NgVertex<I> src = new NgVertex<>(); /** - * Attribute of edge. If you want to obtain attributes in an edge, you need to use “with prop” in the nGQL. + * Attribute of edge. If you want to obtain attributes in an edge, + * you need to use “with prop” in the nGQL. * <br/> * {@link NebulaDaoBasic#shortestPath} default without prop */ @@ -113,5 +114,5 @@ public void setSrc(NgVertex<I> src) { this.src = src; } } - + } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java index 8c2203a4..c1ea68ab 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java @@ -2,55 +2,55 @@ public class NgTriplet<I> { - private I srcId; - private I dstId; - private Object startNode; - private Object edge; - private Object endNode; - - public NgTriplet(Object startNode, Object edge, Object endNode) { - this.startNode = startNode; - this.edge = edge; - this.endNode = endNode; - } - - public I getSrcId() { - return srcId; - } - - public void setSrcId(I srcId) { - this.srcId = srcId; - } - - public I getDstId() { - return dstId; - } - - public void setDstId(I dstId) { - this.dstId = dstId; - } - - public Object getStartNode() { - return startNode; - } - - public void setStartNode(Object startNode) { - this.startNode = startNode; - } - - public Object getEdge() { - return edge; - } - - public void setEdge(Object edge) { - this.edge = edge; - } - - public Object getEndNode() { - return endNode; - } - - public void setEndNode(Object endNode) { - this.endNode = endNode; - } + private I srcId; + private I dstId; + private Object startNode; + private Object edge; + private Object endNode; + + public NgTriplet(Object startNode, Object edge, Object endNode) { + this.startNode = startNode; + this.edge = edge; + this.endNode = endNode; + } + + public I getSrcId() { + return srcId; + } + + public void setSrcId(I srcId) { + this.srcId = srcId; + } + + public I getDstId() { + return dstId; + } + + public void setDstId(I dstId) { + this.dstId = dstId; + } + + public Object getStartNode() { + return startNode; + } + + public void setStartNode(Object startNode) { + this.startNode = startNode; + } + + public Object getEdge() { + return edge; + } + + public void setEdge(Object edge) { + this.edge = edge; + } + + public Object getEndNode() { + return endNode; + } + + public void setEndNode(Object endNode) { + this.endNode = endNode; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 4308497d..571c96ce 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -322,7 +322,7 @@ default int deleteById(I id) { * @param ids 表记录主键列表 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteByIdBatch (Collection<I> ids) { + default int deleteByIdBatch(Collection<I> ids) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); From 11b6cf9d27112383c3c2998c18ed99887a4bdb5b Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Mon, 13 Nov 2023 22:27:14 +0800 Subject: [PATCH 47/56] chore: beetl and anltr4 version upgrade --- CHANGELOG.md | 2 ++ pom.xml | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a911857..dc70090f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,8 @@ This source code is licensed under Apache 2.0 License. ## Dependencies upgrade - nebula-java: 3.5.0 -> 3.6.0 +- beetl: 3.1.8-RELEASE -> 3.15.10.RELEASE +- antlr4: 4.7.2 -> 4.11.1 ## Bugfix diff --git a/pom.xml b/pom.xml index 914607bb..ea97f61e 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> + <beetl.version>3.15.10.RELEASE</beetl.version> </properties> <dependencies> @@ -91,7 +92,22 @@ <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl</artifactId> - <version>3.1.8.RELEASE</version> + <version>${beetl.version}</version> + <exclusions> + <exclusion> + <groupId>com.ibeetl</groupId> + <artifactId>beetl-default-antlr4.9-support</artifactId> + </exclusion> + <exclusion> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.ibeetl</groupId> + <artifactId>beetl-antlr4.11-support</artifactId> + <version>${beetl.version}</version> </dependency> <!-- for nGQL escape in xml --> From c90bcf2051c4fbdeffe93d0e716a928bcd0a4216 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Wed, 15 Nov 2023 03:10:20 +0800 Subject: [PATCH 48/56] fix: disable automatic space switching when the current space is null --- .../ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java | 6 ++++-- ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml | 8 ++++++-- .../ngbatis/demo/repository/DropSpaceDaoTest.java | 6 +++--- .../org/nebula/contrib/ngbatis/proxy/MapperProxy.java | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java index b03a4da9..adc83292 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java @@ -14,9 +14,11 @@ */ public interface DropSpaceDao { - void createSpace(String name); + void useTestSpace(); - void dropSpace(String name); + void createSpace(); + + void dropSpace(); List<String> showTags(); diff --git a/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml index d5033969..b1f068fd 100644 --- a/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml +++ b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml @@ -6,11 +6,15 @@ <mapper namespace="ye.weicheng.ngbatis.demo.repository.DropSpaceDao" space="test_drop"> <delete id="dropSpace"> - drop space ${ p0 }; + drop space test_drop; </delete> + <select id="useTestSpace" space="test"> + RETURN 1; + </select> + <select id="createSpace" space="null"> - create space ${ p0 } ( vid_type = INT64 ); + create space test_drop ( vid_type = INT64 ); </select> <select id="showTags" resultType="java.lang.String"> diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java index a0618792..d2abbd82 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java @@ -22,14 +22,14 @@ class DropSpaceDaoTest { @Test void dropSpace() throws InterruptedException { - String spaceName = "test_drop"; - dao.createSpace(spaceName); + dao.useTestSpace(); + dao.createSpace(); Thread.sleep(10 * 1000); List<String> tags = dao.showTags(); System.out.println(tags); - dao.dropSpace(spaceName); + dao.dropSpace(); } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java index ed6ea024..fcceae1a 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java @@ -319,7 +319,7 @@ private static String[] qlWithSpace(LocalSession localSession, String gql, Strin gql = gql.trim(); String sessionSpace = localSession.getCurrentSpace(); boolean sameSpace = Objects.equals(sessionSpace, currentSpace); - if (!sameSpace) { + if (!sameSpace && currentSpace != null) { qlAndSpace[0] = currentSpace; Session session = localSession.getSession(); ResultSet execute = session.execute(String.format("USE `%s`", currentSpace)); From 0fb7704921e06993de769361e912e8a7a24af19b Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Wed, 15 Nov 2023 04:14:26 +0800 Subject: [PATCH 49/56] v1.2.0-beta --- CHANGELOG.md | 10 +++++++++- README.md | 2 +- ngbatis-demo/pom.xml | 2 +- pom.xml | 2 +- .../nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java | 6 +++--- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc70090f..21c4c043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ This source code is licensed under Apache 2.0 License. - [ ] Springboot 3.x support. -# NEXT +# 1.2.0-beta ## Dependencies upgrade @@ -34,6 +34,13 @@ This source code is licensed under Apache 2.0 License. - beetl: 3.1.8-RELEASE -> 3.15.10.RELEASE - antlr4: 4.7.2 -> 4.11.1 +## Feature + +- feat: support `<nGQL>` include query pieces. ([#212](https://github.com/nebula-contrib/ngbatis/pull/212), via [dieyi](https://github.com/1244453393)) +- feat: extending `NgPath`, when 'with prop' is used in nGQL, edge attributes can be obtained from NgPath. ([#212](https://github.com/nebula-contrib/ngbatis/pull/212), via [dieyi](https://github.com/1244453393)) +- feat: expanding the `insertEdgeBatch` interface in `NebulaDaoBasic`. ([#244](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) +- feat: expanding the `deleteByIdBatch` interface in `NebulaDaoBasic`. ([#247](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) + ## Bugfix - fix: support methods in mapper tags to set space to null. @@ -55,6 +62,7 @@ This source code is licensed under Apache 2.0 License. - fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... > 需要将 `@Param` 移除,或者将 xml 中的参数名改成 注解的参数名,以保证参数名统一 +- fix:class 'ResultSetUtil.java' parse datetime type error. ([#241](https://github.com/nebula-contrib/ngbatis/pull/241), via [爱吃辣条的Jerry](https://github.com/bobobod)) ## Develop behavior change diff --git a/README.md b/README.md index 5908293a..435a551c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This source code is licensed under Apache 2.0 License. </p> - [Ngbatis Docs](https://nebula-contrib.github.io/ngbatis/) -- [Ngbatis 文档](https://corvusye.github.io/ngbatis-docs/) +- [Ngbatis 文档](https://graph-cn.github.io/ngbatis-docs/) ## What is NGBATIS diff --git a/ngbatis-demo/pom.xml b/ngbatis-demo/pom.xml index 1cbe2a65..631b7974 100644 --- a/ngbatis-demo/pom.xml +++ b/ngbatis-demo/pom.xml @@ -50,7 +50,7 @@ <dependency> <groupId>org.nebula-contrib</groupId> <artifactId>ngbatis</artifactId> - <version>1.2.0-SNAPSHOT</version> + <version>1.2.0-beta</version> </dependency> </dependencies> diff --git a/pom.xml b/pom.xml index ea97f61e..d237a2cc 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ <name>ngbatis</name> <groupId>org.nebula-contrib</groupId> <artifactId>ngbatis</artifactId> - <version>1.2.0-SNAPSHOT</version> + <version>1.2.0-beta</version> <developers> <developer> diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 571c96ce..993b74ba 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -291,7 +291,7 @@ default int deleteLogicById(I id) { * @param id 表记录主键 * @return 是否执行成功,成功 1 ,失败 0 */ - default int deleteWithEdgeById(I id) { + default Integer deleteWithEdgeById(I id) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); @@ -306,7 +306,7 @@ default int deleteWithEdgeById(I id) { * @param id 表记录主键 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteById(I id) { + default Integer deleteById(I id) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); @@ -322,7 +322,7 @@ default int deleteById(I id) { * @param ids 表记录主键列表 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteByIdBatch(Collection<I> ids) { + default Integer deleteByIdBatch(Collection<I> ids) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); From 9fd0589e26c61532aafe7ecb2356fd4998156708 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Wed, 15 Nov 2023 04:19:01 +0800 Subject: [PATCH 50/56] v1.2.0-beta --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c4c043..63c2b06f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ This source code is licensed under Apache 2.0 License. - [ ] Expand the function of NebulaDaoBasic - [ ] Add batch interface: - [ ] insertTripletBatch - - [ ] insertEdgeBatch + - [x] insertEdgeBatch - [ ] ... - [ ] Schema support: - [ ] show metas From 4ecec684dd3eef738ba4dcab9d20d24f461f6ae6 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Wed, 15 Nov 2023 04:28:44 +0800 Subject: [PATCH 51/56] v1.2.0-beta --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63c2b06f..949bc1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ This source code is licensed under Apache 2.0 License. ## Feature - feat: support `<nGQL>` include query pieces. ([#212](https://github.com/nebula-contrib/ngbatis/pull/212), via [dieyi](https://github.com/1244453393)) -- feat: extending `NgPath`, when 'with prop' is used in nGQL, edge attributes can be obtained from NgPath. ([#212](https://github.com/nebula-contrib/ngbatis/pull/212), via [dieyi](https://github.com/1244453393)) +- feat: extending `NgPath`, when 'with prop' is used in nGQL, edge attributes can be obtained from NgPath. ([#228](https://github.com/nebula-contrib/ngbatis/pull/228), via [dieyi](https://github.com/1244453393)) - feat: expanding the `insertEdgeBatch` interface in `NebulaDaoBasic`. ([#244](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) - feat: expanding the `deleteByIdBatch` interface in `NebulaDaoBasic`. ([#247](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) From 4887eadc32217b6e3bf6f8b3ef2a7c0cefa55129 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Wed, 15 Nov 2023 13:48:58 +0800 Subject: [PATCH 52/56] chore: modify the 'release' workflow to include Javadoc --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 997a84b4..9f0a8787 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,7 +42,7 @@ jobs: server-password: MAVEN_PASSWORD - name: Publish package - run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true + run: mvn --batch-mode deploy env: MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} From fdd2e89f6164a57ee294b1de5a056eba33420af5 Mon Sep 17 00:00:00 2001 From: Wey Gu <weyl.gu@gmail.com> Date: Wed, 15 Nov 2023 21:44:19 +0800 Subject: [PATCH 53/56] ci: fix mvn deploy gpg signing as title --- .github/workflows/release.yml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9f0a8787..4215d387 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,12 +11,6 @@ jobs: - name: Check out Git repository uses: actions/checkout@v3 - - name: Setup Java - uses: actions/setup-java@v3 - with: - java-version: '8' - distribution: 'temurin' - - name: Install nebula-graph run: | mkdir tmp @@ -30,16 +24,16 @@ jobs: popd popd - - name: Set up Apache Maven Central + - name: Setup Java and Apache Maven Central uses: actions/setup-java@v3 with: java-version: '8' distribution: 'temurin' - gpg-private-key: ${{ secrets.GPG_SECRET }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - server-id: ossrh - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.GPG_SECRET }} # Import GPG key + gpg-passphrase: ${{ secrets.GPG_PASSWORD }} # GPG passphrase + server-id: ossrh # Server ID for Maven Central + server-username: MAVEN_USERNAME # Environment variable for Maven username + server-password: MAVEN_PASSWORD # Environment variable for Maven password - name: Publish package run: mvn --batch-mode deploy From f0a9a1ccc941b67092cd8ebc207439ccd690d227 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Tue, 21 Nov 2023 20:54:43 +0800 Subject: [PATCH 54/56] supports jdk17 --- .github/workflows/doc_en.yaml | 7 +- .../workflows/doc_en_pull_request_dryrun.yaml | 57 ++ .github/workflows/markdown_lint.yaml | 29 + .github/workflows/pull_request.yml | 6 + .github/workflows/release.yml | 28 +- .github/workflows/snapshot.yaml | 28 +- .gitignore | 1 + .markdownlint.json | 8 + CHANGELOG.md | 150 ++-- CONTRIBUTING-CN.md | 21 +- CONTRIBUTING.md | 21 +- EXECUTION-PROCESS.md | 15 +- README-CN.md | 41 +- README.md | 24 +- docs/.nojekyll | 1 + docs/en/md/dev-example/built-in-function.md | 159 ++++ docs/en/md/dev-example/custom-crud.md | 62 +- docs/en/md/dev-example/dao-basic.md | 5 +- docs/en/md/dev-example/parameter-for.md | 11 +- docs/en/md/dev-example/parameter-if.md | 27 +- docs/en/md/dev-example/parameter-use.md | 37 +- docs/en/md/dev-example/prepare.md | 9 +- docs/en/md/quick-start/about.md | 8 +- docs/en/md/quick-start/install.md | 22 +- .../advanced-configuration.md | 8 +- .../step-forward-docs/operation-sequence.md | 78 +- docs/zhCn/md/dev-example/built-in-function.md | 38 +- docs/zhCn/md/dev-example/custom-crud.md | 77 +- docs/zhCn/md/dev-example/dao-basic.md | 3 + docs/zhCn/md/dev-example/multi-tag.md | 6 +- docs/zhCn/md/dev-example/parameter-for.md | 8 + docs/zhCn/md/dev-example/parameter-if.md | 27 +- docs/zhCn/md/dev-example/parameter-use.md | 56 +- docs/zhCn/md/dev-example/prepare.md | 10 +- docs/zhCn/md/dev-example/result-built-in.md | 6 +- docs/zhCn/md/dev-example/result.md | 85 ++- docs/zhCn/md/quick-start/about.md | 5 +- docs/zhCn/md/quick-start/features.md | 38 +- docs/zhCn/md/quick-start/install.md | 50 +- .../advanced-configuration.md | 7 +- .../step-forward-docs/operation-sequence.md | 2 + googl_codestyle.xml => google_codestyle.xml | 0 ngbatis-demo/pom.xml | 4 +- .../weicheng/ngbatis/demo/pojo/Employee.java | 3 +- .../ngbatis/demo/pojo/NoPropertiesVertex.java | 3 +- .../ye/weicheng/ngbatis/demo/pojo/Person.java | 3 +- .../weicheng/ngbatis/demo/pojo/TimeTest.java | 1 - .../ngbatis/demo/repository/DropSpaceDao.java | 25 + .../repository/NgqlInclude4diffMapperDao.java | 11 + .../demo/repository/NgqlIncludeDao.java | 15 + .../demo/repository/TestRepository.java | 9 +- .../repository/resource/TestRepository.java | 4 +- .../src/main/resources/application.yml | 4 + .../src/main/resources/docker-compose.yaml | 377 ++++++++++ .../main/resources/mapper/DropSpaceDao.xml | 24 + .../mapper/NgqlInclude4diffMapperDao.xml | 12 + .../main/resources/mapper/NgqlIncludeDao.xml | 28 + .../main/resources/mapper/TestRepository.xml | 4 +- .../src/main/resources/testgraph.ngql | 7 + .../ngbatis/demo/NebulaBasicDaoTests.java | 80 +- .../demo/NgbatisDemoApplicationTests.java | 17 +- .../demo/repository/DropSpaceDaoTest.java | 35 + .../demo/repository/EmployeeDaoTest.java | 10 +- .../demo/repository/NgqlIncludeTest.java | 30 + .../resource/TestRepositoryTest.java | 9 +- package-lock.json | 706 ++++++++++++++++++ package.json | 20 + pom.xml | 76 +- .../binding/beetl/functions/GetFn.java | 21 + .../binding/beetl/functions/IncludeFn.java | 53 ++ .../ngbatis/handler/NgPathResultHandler.java | 44 +- .../handler/NgVertexResultHandler.java | 15 +- .../ngbatis/io/MapperResourceLoader.java | 61 +- .../contrib/ngbatis/models/ClassModel.java | 9 + .../contrib/ngbatis/models/NgqlModel.java | 33 + .../contrib/ngbatis/models/data/NgPath.java | 55 +- .../ngbatis/models/data/NgTriplet.java | 56 ++ .../contrib/ngbatis/proxy/MapperProxy.java | 21 +- .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 39 +- .../contrib/ngbatis/utils/ReflectUtil.java | 2 +- .../contrib/ngbatis/utils/ResultSetUtil.java | 28 +- src/main/resources/NebulaDaoBasic.xml | 26 +- src/main/resources/beetl.properties | 3 + src/main/resources/ngbatis-mapper.dtd | 41 + .../ngbatis/binding/BeetlTextRenderTest.java | 7 +- 85 files changed, 2952 insertions(+), 360 deletions(-) create mode 100644 .github/workflows/doc_en_pull_request_dryrun.yaml create mode 100644 .github/workflows/markdown_lint.yaml create mode 100644 .markdownlint.json create mode 100644 docs/.nojekyll create mode 100644 docs/en/md/dev-example/built-in-function.md rename googl_codestyle.xml => google_codestyle.xml (100%) create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java create mode 100644 ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java create mode 100644 ngbatis-demo/src/main/resources/docker-compose.yaml create mode 100644 ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml create mode 100644 ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml create mode 100644 ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml create mode 100644 ngbatis-demo/src/main/resources/testgraph.ngql create mode 100644 ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java create mode 100644 ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/GetFn.java create mode 100644 src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java create mode 100644 src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java create mode 100644 src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java create mode 100644 src/main/resources/ngbatis-mapper.dtd diff --git a/.github/workflows/doc_en.yaml b/.github/workflows/doc_en.yaml index fbb11452..d49e3cef 100644 --- a/.github/workflows/doc_en.yaml +++ b/.github/workflows/doc_en.yaml @@ -28,13 +28,14 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - + - name: Checkout frontend code uses: actions/checkout@v3 with: repository: graph-cn/ngbatis-docs path: ngbatis-docs - + ref: 7b17bd88148d39643185ba218e3a18ceb3877428 + - name: Place markdown file run: | cp -r docs/en/md/* ngbatis-docs/docs @@ -46,7 +47,7 @@ jobs: node-version: 18 cache: npm cache-dependency-path: ngbatis-docs/package-lock.json - + - name: Setup Pages uses: actions/configure-pages@v3 - name: Build with VitePress diff --git a/.github/workflows/doc_en_pull_request_dryrun.yaml b/.github/workflows/doc_en_pull_request_dryrun.yaml new file mode 100644 index 00000000..901ddd1d --- /dev/null +++ b/.github/workflows/doc_en_pull_request_dryrun.yaml @@ -0,0 +1,57 @@ +# +name: Dry run Docs Build in PR + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: [master] + paths: + - 'docs/**' + - '.github/workflows/**' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Checkout frontend code + uses: actions/checkout@v3 + with: + repository: graph-cn/ngbatis-docs + path: ngbatis-docs + ref: 7b17bd88148d39643185ba218e3a18ceb3877428 + + - name: Place markdown file + run: | + cp -r docs/en/md/* ngbatis-docs/docs + cp docs/en/vitepress.config.ts ngbatis-docs/docs/.vitepress/config.ts + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + cache-dependency-path: ngbatis-docs/package-lock.json + + - name: Dryrun Build with VitePress + run: | + cd ngbatis-docs + npm ci + npm run docs:build + touch docs/.vitepress/dist/.nojekyll diff --git a/.github/workflows/markdown_lint.yaml b/.github/workflows/markdown_lint.yaml new file mode 100644 index 00000000..1b378303 --- /dev/null +++ b/.github/workflows/markdown_lint.yaml @@ -0,0 +1,29 @@ +# +name: Lint Markdown + +on: + pull_request: + branches: [master] + paths: + - 'docs/**' + - '*.md' + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: npm + - name: Install dependencies and lint markdown + run: | + cd docs + npm ci + npm run lint-md diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 56b92d60..900e0a69 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -10,6 +10,12 @@ on: branches: - master - 'v[0-9]+.*' + paths: + - 'src/**' + - 'ngbatis-demo/**' + - '**/*.xml' + - '*.xml' + - '.github/workflows/**' jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index de22e956..d1f6624e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,12 +11,6 @@ jobs: - name: Check out Git repository uses: actions/checkout@v3 - - name: Install Java and Maven - uses: actions/setup-java@v3 - with: - java-version: '8' - distribution: 'temurin' - - name: Install nebula-graph run: | mkdir tmp @@ -30,10 +24,20 @@ jobs: popd popd - - name: Release Maven package - uses: samuelmeuli/action-maven-publish@v1 + - name: Setup Java and Apache Maven Central + uses: actions/setup-java@v3 with: - gpg_private_key: ${{ secrets.GPG_SECRET }} - gpg_passphrase: ${{ secrets.GPG_PASSWORD }} - nexus_username: ${{ secrets.OSSRH_USER }} - nexus_password: ${{ secrets.OSSRH_PASSWORD }} + java-version: '17' + distribution: 'temurin' + gpg-private-key: ${{ secrets.GPG_SECRET }} # Import GPG key + gpg-passphrase: ${{ secrets.GPG_PASSWORD }} # GPG passphrase + server-id: ossrh # Server ID for Maven Central + server-username: MAVEN_USERNAME # Environment variable for Maven username + server-password: MAVEN_PASSWORD # Environment variable for Maven password + + - name: Publish package + run: mvn --batch-mode deploy + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSWORD }} diff --git a/.github/workflows/snapshot.yaml b/.github/workflows/snapshot.yaml index b21d5079..73f64fec 100644 --- a/.github/workflows/snapshot.yaml +++ b/.github/workflows/snapshot.yaml @@ -2,7 +2,7 @@ name: snapshot on: push: - branches: [ master ] + branches: [ for-jdk17 ] schedule: - cron: '0 6 * * *' @@ -13,10 +13,10 @@ jobs: - name: Check out Git repository uses: actions/checkout@v3 - - name: Install Java and Maven + - name: Setup Java uses: actions/setup-java@v3 with: - java-version: '8' + java-version: '17' distribution: 'temurin' - name: Install nebula-graph @@ -32,10 +32,20 @@ jobs: popd popd - - name: Deploy Snapshot to Maven package - uses: samuelmeuli/action-maven-publish@v1 + - name: Set up Apache Maven Central + uses: actions/setup-java@v3 with: - gpg_private_key: ${{ secrets.GPG_SECRET }} - gpg_passphrase: ${{ secrets.GPG_PASSWORD }} - nexus_username: ${{ secrets.OSSRH_USER }} - nexus_password: ${{ secrets.OSSRH_PASSWORD }} + java-version: '17' + distribution: 'temurin' + gpg-private-key: ${{ secrets.GPG_SECRET }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + + - name: Publish package + run: mvn --batch-mode deploy -Dmaven.javadoc.skip=true + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USER }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSWORD }} diff --git a/.gitignore b/.gitignore index 738fe269..4f2fb8df 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ build/ ### vitepress ### .vitepress +node_modules/ diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..358042de --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "MD013": false, + "MD041": false, + "MD033": false, + "MD024": false, + "MD001": false, +} diff --git a/CHANGELOG.md b/CHANGELOG.md index a092ba5c..0334be44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,14 +6,16 @@ This source code is licensed under Apache 2.0 License. --> # [TODO] + ## Features + - [ ] Expand the function of NebulaDaoBasic - [ ] Add batch interface: - [ ] insertTripletBatch - - [ ] insertEdgeBatch + - [x] insertEdgeBatch - [ ] ... - [ ] Schema support: - - [ ] show metas + - [ ] show metas - [ ] create | alter tag & edge type - [ ] index - [ ] ResultSetUtil more column types support @@ -23,27 +25,53 @@ This source code is licensed under Apache 2.0 License. ## Dependencies upgrade - [x] Springboot 3.x support. -# NEXT +# 1.2.0-JDK-17-beta + ## Dependencies upgrade + - nebula-java: 3.5.0 -> 3.6.0 +- beetl: 3.1.8-RELEASE -> 3.15.10.RELEASE +- antlr4: 4.7.2 -> 4.11.1 + +## Feature + +- feat: support `<nGQL>` include query pieces. ([#212](https://github.com/nebula-contrib/ngbatis/pull/212), via [dieyi](https://github.com/1244453393)) +- feat: extending `NgPath`, when 'with prop' is used in nGQL, edge attributes can be obtained from NgPath. ([#228](https://github.com/nebula-contrib/ngbatis/pull/228), via [dieyi](https://github.com/1244453393)) +- feat: expanding the `insertEdgeBatch` interface in `NebulaDaoBasic`. ([#244](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) +- feat: expanding the `deleteByIdBatch` interface in `NebulaDaoBasic`. ([#247](https://github.com/nebula-contrib/ngbatis/pull/244), via [Sunhb](https://github.com/shbone)) ## Bugfix + +- fix: support methods in mapper tags to set space to null. + - Such as: + + ```xml + <mapper namespace="..."> + <create id="createSpace" space="null"> + create space new_space ( vid_type = INT64 ); + </create> + </mapper> + ``` + - fix: [#190](https://github.com/nebula-contrib/ngbatis/issues/190) Insert failed when tag has no attributes - chore: removing and exclude some packages: log4j related or useless. - fix: [#194](https://github.com/nebula-contrib/ngbatis/issues/194) we can name the interface by `@Component` and `@Resource`, for example: - `@Component("namedMapper")`: use `@Resource("namedMapper$Proxy")` to inject. (since v1.0) - `@Resource("namedComponent")`: use `@Resource("namedComponent")` to inject. (new feature) -- fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. - > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... +- fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. + > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... > 需要将 `@Param` 移除,或者将 xml 中的参数名改成 注解的参数名,以保证参数名统一 +- fix:class 'ResultSetUtil.java' parse datetime type error. ([#241](https://github.com/nebula-contrib/ngbatis/pull/241), via [爱吃辣条的Jerry](https://github.com/bobobod)) + +## Develop behavior change -## Develop behavior change. - Remove deprecated classes and methods: - org.nebula.contrib.ngbatis.binding.DateDeserializer - org.nebula.contrib.ngbatis.binding.DefaultArgsResolver#customToJson - Dependencies changing: > 如果项目中有用到,且出现相关类找不到的情况,请自行引入 - Exclude: + ```xml <dependency> <groupId>org.springframework.boot</groupId> @@ -66,6 +94,7 @@ This source code is licensed under Apache 2.0 License. ``` - Removing: + ```xml <!-- Why: make it possible to use undertow as web server --> <dependency> @@ -81,7 +110,7 @@ This source code is licensed under Apache 2.0 License. <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> - ``` + ``` # 1.1.6 ## Dependencies @@ -89,7 +118,9 @@ This source code is licensed under Apache 2.0 License. # 1.1.5 -## Bugfix + +## 1.1.5 Bugfix + - fix: [#176](https://github.com/nebula-contrib/ngbatis/issues/176) use double quote instead of the original single quote in valuaFmt function - fix: [#181](https://github.com/nebula-contrib/ngbatis/issues/181) when node has multi tag, can not update by subclass - updateById @@ -100,14 +131,18 @@ This source code is licensed under Apache 2.0 License. - fix: [#185](https://github.com/nebula-contrib/ngbatis/issues/185) improve the accuracy of datetime to milliseconds # 1.1.4 -## Develop behavior change. + +## 1.1.4 Behavior Changes + - When a field is declared by java.util.Date, it is no longer allowed to set a value using Timestamp > 当字段由java.util.Date声明时,不再允许使用java.sql.Timestamp设值 -## Bugfix +## 1.1.4 Bugfix + - fix: data error for date type in the database.[#102](https://github.com/nebula-contrib/ngbatis/issues/102) ## Feature + - Clear time type mapping. db type | java type @@ -119,68 +154,86 @@ This source code is licensed under Apache 2.0 License. duration | java.time.Duration # 1.1.3 -## Bugfix + +## 1.1.3 Bugfix + - fix: make the error message clearer when 'use space' failed [#150](https://github.com/nebula-contrib/ngbatis/issues/150) - fix: sessionPool is null when the space name only declared in yml -## Dependencies upgrade + +## 1.1.3 Dependencies upgrade + - nebula-java: 3.4.0 -> 3.5.0 # 1.1.2 -## Develop behavior change. + +## 1.1.2 Behavior Changes + - If an entity type is another entity type's super class, all attribute are being required in database schema except `@Transient` > 如果一个实体类是另一个实体类的父类,则其所有除了注解`@Transient` 了的属性,都需要在数据库中声明。 -## Bugfix -- fix: when vertex has multi tags cannot set value properly.[#120](https://github.com/nebula-contrib/ngbatis/issues/120) +## 1.1.2 Bugfix + +- fix: when vertex has multi tags cannot set value properly.[#120](https://github.com/nebula-contrib/ngbatis/issues/120) - fix: `ng.join` bug [#122](https://github.com/nebula-contrib/ngbatis/issues/122) -## Features + +## 1.1.2 Features + - feat: multi tags support for vertex inserting. - feat: provide default data structure for edge \ vertex \ path \ sub-graph, and their result handler. #103 #118 - feat: NebulaDaoBasic shortest path support. #118 - feat: ng.valueFmt support escape ( default true ). Use `ValueFmtFn.setEscape( false );` to disable this feature. - feat: add config to use `nebula-java` session pool - ``` + + ```yaml nebula: ngbatis: use-session-pool: true - ``` + ``` + +## 1.1.2 Dependencies upgrade -## Dependencies upgrade - nebula-java: 3.3.0 -> 3.4.0 # 1.1.1 + - fixed #89 BigDecimal / Set / Collection serialization to NebulaValue #97 # 1.1.0 -## Features -- springcloud+nacos support #55 -- add upsert tag/edge function #82 + +## 1.1.1 Features + +- springcloud+nacos support #55 +- add upsert tag/edge function #82 - support #39, use @javax.persistence.Transient #43 ## Enhancement -- enhanced: #64 `debug log` print current space in session before switch #79 -- enhanced: NebulaDaoBasic default impls can be overwritten by xml #76 -- optimize #69 display exception detail & enable NebulaDaoBasic to support space switching #70 -- docs typo #52 -## Bugfix -- fixed #89 splitting param serialization into two forms, json and NebulaValue #92 -- fixed #78 use space and gql are executed together incorrect in 3.3.0 #87 -- fixed #73 `selectById` use id value embedding instead of cypher parameter #74 -- fixed #65 `selectByIds` use id values embedding instead of cypher param #67 -- fixed the error of "ng.id" when id is in super class #62 -- fixed #51 The node params support the direct use of the ID value when insert edge #60 -- fixed #56 make it work well when returnType is Map and result is null #58 -- fixed #47 console bug when result type is basic type #48 +- enhanced: #64 `debug log` print current space in session before switch #79 +- enhanced: NebulaDaoBasic default impls can be overwritten by xml #76 +- optimize #69 display exception detail & enable NebulaDaoBasic to support space switching #70 +- docs typo #52 + +## 1.1.1 Bugfix + +- fixed #89 splitting param serialization into two forms, json and NebulaValue #92 +- fixed #78 use space and gql are executed together incorrect in 3.3.0 #87 +- fixed #73 `selectById` use id value embedding instead of cypher parameter #74 +- fixed #65 `selectByIds` use id values embedding instead of cypher param #67 +- fixed the error of "ng.id" when id is in super class #62 +- fixed #51 The node params support the direct use of the ID value when insert edge #60 +- fixed #56 make it work well when returnType is Map and result is null #58 +- fixed #47 console bug when result type is basic type #48 # 1.1.0-rc + 增加了一些内置函数可以在 xml 中使用: + - ng.valueFmt > 对不定类型的数据值进行格式化,忽略是否追加单引号及日期格式化,直接传原始 java类型即可 参数位 | 参数说明 | 类型 | 是否必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y | + 1 | 值 | Object | Y | 2 | 如果是字符串是否在前后追加 .* 形成模糊查询 | boolean | N | false - ng.schemaFmt @@ -195,17 +248,15 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 与Schema对应的实体类对象 | Object | Y + 1 | 与Schema对应的实体类对象 | Object | Y 2 | 类模型,使用 `ng_cm` 传入 | ClassModel | N | null - - - ng.pkField > 用于获取 主键属性,java.lang.reflect.Field 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类类型 | Class<?> | Y + 1 | 实体类类型 | Class<?> | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | false - ng.pkName @@ -213,7 +264,7 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.entityType @@ -222,14 +273,14 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y - ng.fieldNames > 获取属性名集合(不包括主键) 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.id @@ -237,12 +288,13 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | true 3 | 如果值为空,true会通过主键生成器返回新值,false 时 返回空 | Boolean | N | true - ng.kv > 通过实体对象或者获取多个集合 + > > - columns 列名集合 > - valueNames 属性名集合 > - values 值集合 @@ -250,7 +302,7 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 参数名前缀 | String | N | null 3 | 是否排除主键 | Boolean | N | true 4 | 是否排除空值 | Boolean | N | true @@ -261,19 +313,17 @@ This source code is licensed under Apache 2.0 License. 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 待格式化的集合 | Iterable | Y - 2 | 元素间的分隔符 | String | N | `,` + 1 | 待格式化的集合 | Iterable | Y + 2 | 元素间的分隔符 | String | N | `,` 3 | 函数名,各元素拼接前,可进行函数名指定的格式化函数先行格式化,再拼接 | String | N | null - - ng.ifStringLike > 类型为字符串时,前后拼接 `.*` 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y + 1 | 值 | Object | Y 2 | 属性类型 | Object | N | null 3 | 属性名,用于不将值明文写在 ngql 中,而使用参数名,让 nebula 在参数中取值 | String | N | null - # 1.1.0-beta diff --git a/CONTRIBUTING-CN.md b/CONTRIBUTING-CN.md index f8c12ce4..fb4148b0 100644 --- a/CONTRIBUTING-CN.md +++ b/CONTRIBUTING-CN.md @@ -1,21 +1,40 @@ # 如何贡献代码? +## Markdown 格式检查 + +提交带有 `.md` 后缀的文件前,可以先进行格式检查。 + +```bash +npm ci +npm run lint-md +``` + +如遇到任何格式错误,请在提交前修复。大多数情况下,内置的格式化工具可能会有所帮助。 + +```bash +npm run format-md +``` + ## 环境要求 + - JDK >= 8 - NebulaGraph > v3.0 - Springboot 2.x - Maven ## 克隆仓库 + 1. 在仓库主页右上角fork到自己的仓库 2. 从自己的仓库中clone到本地 ## 开发步骤 + 1. 如果是第一次贡献,请在 pom.xml 添加作者信息 2. 按你的想法开发功能,把好功能固化下来与其他开发者分享 3. 在 `CHANGELOG.md` 中描述新增的功能及使用方式、场景 ## 运行测试用例及代码风格检查 + 1. 在`ngbatis-demo/test`中运行单元测试 2. 使用maven插件做代码风格检查:`maven->plugins->checkstyle->checkstyle:check` @@ -23,4 +42,4 @@ ## 体会分享所带来的快乐 -> 有任何问题,请放心提issue \ No newline at end of file +> 有任何问题,请放心提issue diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50fa49f5..8fca0f6d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,22 @@ # How To Contribute +## Markdown Lint + +We could lint markdown files before commiting. + +```bash +npm ci +npm run lint-md +``` + +In case of any linting errors, please fix them before commiting. The buildin formatter may help in most cases. + +```bash +npm run format-md +``` + ## Version base + You should be having: - JDK >= 17 - NebulaGraph > v3.0 @@ -8,15 +24,18 @@ You should be having: - Maven ## Clone the repository + 1. Click the `fork` button on the top right of this page. 2. Download the project to your machine. ## Start develop + 1. Add developer in pom.xml if you are the first time to contributing. 2. Use your ideas to make ngbatis better. 3. Describe changes in `CHANGELOG.md` ## Make sure everything goes well + 1. Run unit tests in `ngbatis-demo/test` 2. Use maven plugins to check code style: `maven->plugins->checkstyle->checkstyle:check` @@ -24,4 +43,4 @@ You should be having: ## Experience the joy brought by sharing -> If you have any questions, issue please. \ No newline at end of file +> If you have any questions, issue please. diff --git a/EXECUTION-PROCESS.md b/EXECUTION-PROCESS.md index 33a64e26..fa52131a 100644 --- a/EXECUTION-PROCESS.md +++ b/EXECUTION-PROCESS.md @@ -6,7 +6,9 @@ This source code is licensed under Apache 2.0 License. --> # 框架执行过程详述 + ## 初始化 + 1. 交由Springboot启动扫描,入口声明配置为:[spring.factories](./src/main/resources/META-INF/spring.factories) , 2. 启动类为:[NgbatisContextInitialize](src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java) 3. 初始化过程 @@ -35,9 +37,11 @@ This source code is licensed under Apache 2.0 License. > 至此完成 ngbatis 动态代理的初始化过程 ## 应用配置,主类 [Env](src/main/java/org/nebula/contrib/ngbatis/Env.java) + 1. 声明nGQL参数解析器,默认方案使用 beetl 模板引擎进行解析。[BeetlTextRender](./src/main/java/org/nebula/contrib/ngbatis/binding/BeetlTextRender.java) > 替换方式为:自行实现 [TextResolver](src/main/java/org/nebula/contrib/ngbatis/TextResolver.java)并以 @Primary 的方式交由spring管理 2. 指定主键生成器(vertex id 与 edge rank 值设置器),可使用时间戳主键生成来获取主键,但建议按自身应用的架构自行实现主键生成。 + ```java @Configuration public class PkGeneratorConfig { @@ -47,10 +51,11 @@ This source code is licensed under Apache 2.0 License. } } ``` -3. 可通过继承[AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java)进行更多类型结果的实体化 +3. 可通过继承[AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java)进行更多类型结果的实体化 ## 运行时 + 1. 业务方通过反转注入的方式,将动态代理类注入到业务类中。 2. 业务类调用实际方法,并传入参数 3. 动态代理执行 MapperProxy.invoke( 接口名, 方法名, 参数列表 ) @@ -60,13 +65,9 @@ This source code is licensed under Apache 2.0 License. 4. 结果集处理,结果集处理器路由[ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver.java),默认为 [DefaultResultResolver](./src/main/java/org/nebula/contrib/ngbatis/binding/DefaultResultResolver.java),由方法模型中接口声明的返回值与额外声明的泛型resultType共同决定采用何种[ResultHandler](src/main/java/org/nebula/contrib/ngbatis/ResultHandler.java)对结果进行处理。**在这个小步骤中,完成 ORM 过程。** ## 开发者使用思路(如无特殊需求,复杂拓展请见【应用配置】) + 1. 指定主键生成器,参考【应用配置.2】 -2. 创建 XXXDao.java +2. 创建 XXXDao.java 3. 创建 XXXDao.xml 并指定 namespace 为 XXXDao.java 4. 在 XXXDao.xml 中编写 nGQL 5. 业务调用时直接注入 XXXDao,调用对应方法即可获取并执行对应 nGQL,无需处理结果集,便能拿到所需 实体对象 - - - - - diff --git a/README-CN.md b/README-CN.md index 2392882c..a2118ae9 100644 --- a/README-CN.md +++ b/README-CN.md @@ -11,7 +11,8 @@ This source code is licensed under Apache 2.0 License. <br> <a href="README.md">English</a> | 中文 </p> -- [Ngbatis Docs](https://corvusye.github.io/ngbatis-docs/#/) +- [Ngbatis Docs](https://nebula-contrib.github.io/ngbatis/) +- [Ngbatis 文档](https://corvusye.github.io/ngbatis-docs/) ## NGBATIS是什么? @@ -23,13 +24,17 @@ This source code is licensed under Apache 2.0 License. 请看设计文档 [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) ## 项目要求 + - Springboot - Maven - Java 8+ ## 如何使用(可在克隆代码后,参考 ngbatis-demo 项目) + ### 在项目引入 - - Maven + +- Maven + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -37,15 +42,19 @@ This source code is licensed under Apache 2.0 License. <version>1.1.5</version> </dependency> ``` - - Gradle + +- Gradle + ```groovy implementation 'org.nebula-contrib:ngbatis:1.1.5' ``` -### 参考 [【ngbatis-demo】](./ngbatis-demo),与springboot无缝集成。在该项目的 test 中还有api的样例。在开发过程中每增加一个特性也都会同步更新ngbatis-demo的用例。 +### 参考 [【ngbatis-demo】](./ngbatis-demo),与springboot无缝集成。在该项目的 test 中还有api的样例。在开发过程中每增加一个特性也都会同步更新ngbatis-demo的用例 ### 配置数据库 + 在 application.yml 中添加配置 **将数据源修改成可访问到的NebulaGraph** + ```yml nebula: ngbatis: @@ -68,7 +77,9 @@ nebula: min-cluster-health-rate: 1.0 enable-ssl: false ``` + ### 扫描动态代理的 bean + ```java @SpringBootApplication(scanBasePackages = { "org.nebula", "your.domain"}) public class YourApplication { @@ -77,12 +88,16 @@ public class YourApplication { } } ``` + > 如果项目中使用的是 SpringCloud, -> 请使用`@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` +> 请使用`@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` ## 日常开发示例 + ### 自己编写 nGQL (MyBatis的思路) + #### 声明数据访问接口 + ```java package ye.weicheng.ngbatis.demo.repository; @@ -101,8 +116,11 @@ public interface TestRepository { } ``` + #### 编写数据访问语句 + resource/mapper/TestRepository.xml + ```xml <mapper namespace= @@ -154,6 +172,7 @@ resource/mapper/TestRepository.xml ### 使用基类自带的 nGQL 实现图的基本操作(MyBatis-plus)的思路 #### model-vertex + ```java package com.example.model.vertex.Person; @@ -169,7 +188,9 @@ public class Person { private Integer age; } ``` + #### model-edge + ```java package com.example.model.edge.Like; @@ -188,6 +209,7 @@ public class Like { ``` #### dao + ```java package com.example.dao; @@ -196,7 +218,9 @@ import com.example.model.vertex.Person; public interface PersonDao extends NebulaDaoBasic<Person, String>{} ``` + #### xml(不可缺少) + ```xml <mapper namespace= @@ -204,7 +228,9 @@ public interface PersonDao extends NebulaDaoBasic<Person, String>{} > </mapper> ``` + #### service + ```java package com.example.service; @@ -266,8 +292,9 @@ public class PersonServiceImpl { ``` ## 特别声明的上游项目 -- [beetl](https://gitee.com/xiandafu/beetl), BSD-3, Beetl模板引擎是项目很重要的组成部分(as is). +- [beetl](https://gitee.com/xiandafu/beetl), BSD-3, Beetl模板引擎是项目很重要的组成部分(as is). ## 开源协议 -项目遵循 [Apache License, Version 2.0, January 2004](https://www.apache.org/licenses/LICENSE-2.0) 开源协议。 \ No newline at end of file + +项目遵循 [Apache License, Version 2.0, January 2004](https://www.apache.org/licenses/LICENSE-2.0) 开源协议。 diff --git a/README.md b/README.md index c3b0bd4d..435a551c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ This source code is licensed under Apache 2.0 License. <br> English | <a href="README-CN.md">中文</a> </p> -- [Ngbatis Docs](https://graph-cn.github.io/ngbatis-docs/) +- [Ngbatis Docs](https://nebula-contrib.github.io/ngbatis/) +- [Ngbatis 文档](https://graph-cn.github.io/ngbatis-docs/) ## What is NGBATIS @@ -24,6 +25,7 @@ If you prefer JPA, [graph-ocean](https://github.com/nebula-contrib/graph-ocean) See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) ## Requirements + - Springboot - Maven - Java 8+ @@ -34,6 +36,7 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) - Include in your `pom.xml` - Maven + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -41,7 +44,9 @@ See [EXECUTION-PROCESS.md](./EXECUTION-PROCESS.md) <version>1.1.5</version> </dependency> ``` + - Gradle + ```groovy implementation 'org.nebula-contrib:ngbatis:1.1.5' ``` @@ -74,6 +79,7 @@ nebula: min-cluster-health-rate: 1.0 enable-ssl: false ``` + - Dynamically register beans ```java @@ -84,12 +90,16 @@ public class YourApplication { } } ``` -> If SpringCloud is used in your project, + +> If SpringCloud is used in your project, > please use `@ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} )` instead. ## Examples + ### a. The MyBatis fashion(compose nGQL queries) + #### a.1 Declare the data access interface + ```java package ye.weicheng.ngbatis.demo.repository; @@ -108,7 +118,9 @@ public interface TestRepository { } ``` + #### a.2 The query statments + `resource/mapper/TestRepository.xml` ```xml @@ -162,6 +174,7 @@ public interface TestRepository { ### b. The MyBatis-plus fashion #### b.1 model-vertex + ```java package com.example.model.vertex.Person; @@ -177,7 +190,9 @@ public class Person { private Integer age; } ``` + #### b.2 model-edge + ```java package com.example.model.edge.Like; @@ -196,6 +211,7 @@ public class Like { ``` #### b.3 dao + ```java package com.example.dao; @@ -204,6 +220,7 @@ import com.example.model.vertex.Person; public interface PersonDao extends NebulaDaoBasic<Person, String>{} ``` + #### b.4 xml > Note, this is a mandatory requirement. @@ -215,7 +232,9 @@ public interface PersonDao extends NebulaDaoBasic<Person, String>{} > </mapper> ``` + #### b.5 service + ```java package com.example.service; @@ -280,7 +299,6 @@ public class PersonServiceImpl { - [beetl](https://gitee.com/xiandafu/beetl), BSD-3, we proudly use the beetl template language as our template engine, which is consumed in binary package(as is). - ## License NGBATIS is under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/docs/.nojekyll @@ -0,0 +1 @@ + diff --git a/docs/en/md/dev-example/built-in-function.md b/docs/en/md/dev-example/built-in-function.md new file mode 100644 index 00000000..8bff9c1c --- /dev/null +++ b/docs/en/md/dev-example/built-in-function.md @@ -0,0 +1,159 @@ +# Built-in Functions and Variables + +## How to use built-in functions and variables + +```java +package your.domain; + +public interface PersonDao { + void insertPerson( Person person ); +} +``` + +```xml +<mapper namespace="your.domain.PersonDao"> + + <insert id="insertPerson"> + @var kv = ng.kv( ng_args[0], '', true, true ); + @var id = ng.id( ng_args[0] ); + @var tagName = ng.tagName( ng_args[0] ); + INSERT VERTEX `${ tagName }` ( + ${ ng.join( @kv.columns, ",", "ng.schemaFmt" ) } + ) + VALUES ${ id } : ( + ${ ng.join( @kv.values ) } + ); + </insert> + +</mapper> +``` + +> In this example, built-in functions such as `ng.kv`, `ng.id`, `ng.tagName`, `ng.join`, `ng.schemaFmt`, and the built-in parameter `ng_args` are used. +> After understanding the usage, we will further introduce the functions in the following content. + +## Built-in Variables + +- ng_cm ClassModel Dao interface class model, making it easier to get more class information in the xml (1.1.0-rc) +- ng_mm MethodModel Dao interface method model, making it easier to get method information in the xml, including input parameter types. (1.1.0-rc) +- ng_args The original parameters passed to the Dao interface, before serialization. (1.1.0-rc) + +## Built-in Functions + +- ng.valueFmt + +> Format data values of uncertain types, ignoring whether to append single quotes and date formatting, and directly pass the original java type + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Value | Object | Y | + 2 | If it is a string, whether to append .* before and after to form a fuzzy query | boolean | N | false + +> Starting from v1.1.2, string types are escaped by default, which can be turned off using: `ValueFmtFn.setEscape( false )` + +- ng.schemaFmt + +> Add **`** before and after the schema name to avoid conflicts with database keywords + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Schema name, such as tagName, edgeName, propertyName | Object | Y + +- ng.tagName + +> Used to get the tag name from the entity class or Dao interface + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object corresponding to the Schema | Object | Y + 2 | Class model, pass in using `ng_cm` | ClassModel | N | null + +- ng.pkField + +> Used to get the primary key attribute, java.lang.reflect.Field + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class type | Class<?> | Y + 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | false + +- ng.pkName + +> Used to get the primary key name, String + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Use column name when true, use attribute name when false | Boolean | N | true + +- ng.entityType + +> Used to get the entity class type + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + +- ng.fieldNames + +> Get the attribute name collection (excluding primary key) + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Use column name when true, use attribute name when false | Boolean | N | true + +- ng.id + +> Get the id value + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | If there is no primary key, whether to report an error and interrupt | Boolean | N | true + 3 | If the value is empty, return a new value generated by the primary key generator when true, return null when false | Boolean | N | true + +- ng.kv + +> Get multiple collections through the entity object +> +> - columns Column name collection +> - valueNames Attribute name collection +> - values Value collection +> - types Attribute types + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Entity class object | Object | Y + 2 | Parameter name prefix | String | N | null + 3 | Exclude primary key | Boolean | N | true + 4 | Exclude null values | Boolean | N | true + 5 | If there is no primary key, whether to report an error and interrupt | Boolean | N | true + +- ng.join + +> Format the collection + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Collection to be formatted | Iterable | Y + 2 | Separator between elements | String | N | `,` + 3 | Function name, before each element is concatenated, it can be formatted by the specified formatting function and then concatenated | String | N | null + +- ng.ifStringLike + +> When the type is a string, prepend and append `.*` + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | Value | Object | Y + 2 | Attribute type | Object | N | null + 3 | Attribute name, used to not write the value in plain text in ngql, but use the parameter name to let nebula take the value from the parameters | String | N | null + +- ng.include + +> Reference nGQL snippet + + Parameter Position | Parameter Description | Type | Required | Default Value + ---|---|---|---|--- + 1 | The nGQL snippet ID to be referenced.<br/>To reference nGQL snippets from other mappers, add the namespace of the snippet before the snippet ID, e.g., your.domain.TestDao.nGQL-ID | String | Y + 2 | Additional parameters when referencing nGQL snippets, which will be used preferentially when generating statements | Object | N | null diff --git a/docs/en/md/dev-example/custom-crud.md b/docs/en/md/dev-example/custom-crud.md index cffd0b5c..e598719a 100644 --- a/docs/en/md/dev-example/custom-crud.md +++ b/docs/en/md/dev-example/custom-crud.md @@ -2,8 +2,10 @@ - > When using this method, the familiarity with nGQL and cypher will be higher. Developers who are not familiar with it can learn about it through【[What Is nGQL](https://docs.nebula-graph.io/3.6.0/3.ngql-guide/1.nGQL-overview/1.overview/)】. - > In addition, the template engine used here is Beetl. + > > - [Beetl Docs-Delimiters And Placeholder Symbols](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947), mainly look at placeholders. Ngbatis has made variable settings. If it is only parameter filling, you can ignore the use of delimiters. 【See [[Param Usage](./parameter-use)] for details】 However, parameter condition control and parameter loop delimiter are almost inevitable. Due to the difference in configuration of `Beetl` in `ngbatis`, if the delimiter is involved in the document, the `<% %>` will be replaced by `@ \n`, for example: +> > ```diff > - <%if ( aBool ) { > - @@ -12,16 +14,18 @@ > + > + @} > ``` - > - [Beetl Docs-Functions Used to Process Parameters](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) +> + > - [Beetl Docs-Functions Used to Process Parameters](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) > - [Beetl Docs-Condition Control Statements](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)【See [Param Condition Control](./parameter-if) for details】 > - [Beetl Docs-Loop Statements](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)【See [Param Loop](./parameter-for) for details】 > - [Beetl-Online test widget](http://ibeetl.com/beetlonline/) - The same as [By Basic DAO](./dao-basic), We need to create a XXXDao.java file and XXXDao.xml file. ## Creating file in Dao layer -### Create a Dao corresponding to Person. If you do not need to use the basic class method, it is unnecessary to inherit NebulaDaoBasic. + +### Create a Dao corresponding to Person. If you do not need to use the basic class method, it is unnecessary to inherit NebulaDaoBasic + ```java package your.domain; @@ -33,29 +37,75 @@ public interface PersonDao { ``` ### Create a file named PersonDao.xml file. The default location is: `/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> </mapper> ``` + > XXXDao.java does not need to be annotated by `@Mapper` or `@Component`, it will be discovered by namespace and automatically registered as a bean. > The premise is that the namespace needs to be in the scanBasePackages value under the @SpringBootApplication annotation. > For example: @SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) -## How to let Java programs execute ` nGQL | cypher` through ngbatis +## How to let Java programs execute `nGQL | cypher` through ngbatis + +### Take a simple query statement as an example -### Take a simple query statement as an example: #### Adding interface in PersonDao.java + ```java Integer select1(); ``` + > In the current version, the return value type and method parameter type of the interface. If it is a basic type, only the wrapper class is supported. For example, please write int as Integer. #### Adding a tag in PersonDao.xml + ```xml <select id="select1"> RETURN 1 </select> ``` -> Integer result = personDao.select1(); // result : 1 \ No newline at end of file +> Integer result = personDao.select1(); // result : 1 + +## Referencing an nGQL Fragment + +> Reference a statement like MyBatis's include tag. + +NgBatis uses the built-in function `ng.include` for referencing. The description of `ng.include` can be found in [Ngbatis Built-in Functions and Variables](./built-in-function). + +### Define Dao Interface + +```xml + <!-- Omit this if the space is consistent with the declaration in the yml file --> + <mapper namespace="your.domain.TestDao" space="test"> + + <!-- Define nGQL fragments anywhere within the mapper node in the XML file --> + <nGQL id="my-ngql-id"> + ${myInt} + </nGQL> + + <!-- Define interface method statement --> + <select id="returnMyInt" resultType="java.lang.Integer"> + RETURN @ng.include('my-ngql-id'); + </select> + + <!-- extra param --> + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('my-ngql-id',{'myInt':age}); + </nGQL> + + </mapper> +``` + +nGQL fragments automatically inherit the parameters passed by the Dao method and can be used directly within the nGQL fragment. You can also specify additional parameters on the `ng.include` function, which will be used with higher priority when generating statements. See the example above. + +nGQL fragments are not limited in hierarchy, and an nGQL fragment can reference another nGQL fragment. However, considering performance, it is not recommended to have too many levels of nGQL statement references. + +If you need to reference an nGQL fragment from another mapper, you need to prepend the namespace of the fragment to the fragment ID when using the `ng.include` function, like this: `@ng.include('your.domain.XxxDao.nGQL-ID');` diff --git a/docs/en/md/dev-example/dao-basic.md b/docs/en/md/dev-example/dao-basic.md index eddc02ae..3e35d6fc 100644 --- a/docs/en/md/dev-example/dao-basic.md +++ b/docs/en/md/dev-example/dao-basic.md @@ -1,6 +1,7 @@ # By Basic DAO ## Create a Dao corresponding to `Person` and extends NebulaDaoBasic + ```java package your.domain; @@ -12,6 +13,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## Create a file named `PersonDao.xml`. The default location is `/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -19,6 +21,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## Examples in the service layer + ```java @Service @@ -92,4 +95,4 @@ public class PersonServiceImpl { } -``` \ No newline at end of file +``` diff --git a/docs/en/md/dev-example/parameter-for.md b/docs/en/md/dev-example/parameter-for.md index 908fccd0..802a457d 100644 --- a/docs/en/md/dev-example/parameter-for.md +++ b/docs/en/md/dev-example/parameter-for.md @@ -2,6 +2,7 @@ > There is a big difference between ngbatis and mybatis in the loop part, and the loop syntax of Beetl is used. Please refer to official documents for details.【[1.10 Loop statement](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)】 > Due to the difference in configuration of `Beetl` in `ngbatis`, the `<% %>` will be replaced by `@ \n`, for example: + ```diff - <%for ( item in list ) { - @@ -12,7 +13,9 @@ ``` ## Looping in Map , which can be used for dynamic query + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // person: { "name": "Diana", "gender": "F" } @@ -20,6 +23,7 @@ ``` - PersonDao.xml + ```xml <select id="selectByPerson"> MATCH (n: person) @@ -35,7 +39,9 @@ ``` ## Looping in List , which can be used for batch processing + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // personList: [{"gender":"F","name":"Diana"},{"gender":"M","name":"Tom"},{"gender":"F","name":"Jerry"}] @@ -43,11 +49,13 @@ ``` - The parameter is : + ```json :param personList => [{"gender":"F","name":"Diana"},{"gender":"M","name":"Tom"},{"gender":"F","name":"Jerry"}] ``` - PersonDao.xml + ```xml <insert id="insertPersonList"> @for ( p in personList ) { @@ -56,7 +64,8 @@ </insert> ``` -- The statements to be executed are: +- The statements to be executed are: + ```sql INSERT VERTEX `person` ( name, gender ) VALUES 'Diana' : ( 'Diana', 'F' ); INSERT VERTEX `person` ( name, gender ) VALUES 'Tom' : ( 'Tom', 'M' ); diff --git a/docs/en/md/dev-example/parameter-if.md b/docs/en/md/dev-example/parameter-if.md index 5525ba77..af41348f 100644 --- a/docs/en/md/dev-example/parameter-if.md +++ b/docs/en/md/dev-example/parameter-if.md @@ -2,6 +2,7 @@ > Syntax reference:【[Beetl-Condition Control](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)】 > Due to the difference in configuration of `Beetl` in `ngbatis`, the `<% %>` will be replaced by `@ \n`, for example: + ```diff - <%if ( aBool ) { - @@ -12,12 +13,15 @@ ``` ## Use of Ternary Expressions + - PersonDao.java + ```java Person selectByNameIfNotEmpty( String name ); ``` - PersonDao.xml + ```xml <select id="selectByNameIfNotEmpty"> MATCH (n: person) @@ -29,12 +33,16 @@ ``` ## Use of if + - PersonDao.java + ```java // params = { age: 18 } Person selectByNameAndAge( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByNameAndAge"> MATCH (n: person) @@ -49,14 +57,18 @@ LIMIT 1 </select> ``` + ## Use of if-else + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -72,13 +84,16 @@ ``` ## Use of switch-case + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -97,16 +112,20 @@ LIMIT 1 </select> ``` + - > **Attention**: the switch variable placed here cannot be null ## Use of select case + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByGender( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -122,15 +141,17 @@ </select> ``` - ## Use of decode + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -144,5 +165,7 @@ LIMIT 1 </select> ``` + ## Conclusion -At this time, the methods that can be used for condition control are basically introduced. Judgment can only be made when inputting parameters. The return value cannot be controlled by conditions. \ No newline at end of file + +At this time, the methods that can be used for condition control are basically introduced. Judgment can only be made when inputting parameters. The return value cannot be controlled by conditions. diff --git a/docs/en/md/dev-example/parameter-use.md b/docs/en/md/dev-example/parameter-use.md index a388d73c..c2296345 100644 --- a/docs/en/md/dev-example/parameter-use.md +++ b/docs/en/md/dev-example/parameter-use.md @@ -7,15 +7,20 @@ Next, in this section, we will introduce how to pass parameters to the statement ## Read Parameters in `nGQL | cypher` ### Named Parameters +> > The parameters are annotated by @Param. ( org.springframework.data.repository.query.Param ) +> #### Basic Types + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("name") String param ); ``` - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -26,12 +31,16 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` #### POJO or Map + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("person") Person person ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -40,20 +49,24 @@ Next, in this section, we will introduce how to pass parameters to the statement LIMIT 1 </select> ``` + > Parameter reading supports `.` operator ### Anonymous Parameters + - If there is no @Param annotation in the parameters declared in the interface, the index is used to obtain, that is: $p0、$p1、$p2、$p3 ... - When the length of the parameter list is 1 and the type is POJO or Map, the attribute can be read directly +#### Basic Type -#### Basic Types - PersonDao.java + ```java Person selectByName( String name ); ``` - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -64,12 +77,17 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` #### POJO or Map -##### When there is only one parameter: + +##### When there is only one parameter + - PersonDao.java + ```java Person selectByName( Person person ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -79,13 +97,17 @@ Next, in this section, we will introduce how to pass parameters to the statement </select> ``` -##### When there are two or more parameters: +##### When there are two or more parameters + - PersonDao.java + ```java // params = { age: 18 } Person selectByName( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByName"> MATCH (n: person) @@ -96,16 +118,22 @@ Next, in this section, we will introduce how to pass parameters to the statement </select> ``` -### The parameter acquisition of the collection type is consistent with the basic types. +### The parameter acquisition of the collection type is consistent with the basic types + - When anonymous, use $p0,$p1,...; - When naming, directly use the parameter name in the annotation; - If it is a collection of basic types, it can be directly passed in without complex processing. + --- + - PersonDao.java + ```java List<Person> findByIds( List<String> names ); ``` + - PersonDao.xml + ```xml <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -115,4 +143,5 @@ Next, in this section, we will introduce how to pass parameters to the statement ``` ## Conclusion + This completes the general introduction of parameter acquisition. If you have requirements for condition control and traversal after obtaining parameters, please move to【[Param Condition Control](./parameter-if)】、【[Param Loop](./parameter-for)】 diff --git a/docs/en/md/dev-example/prepare.md b/docs/en/md/dev-example/prepare.md index 5a07f3b9..02348f84 100644 --- a/docs/en/md/dev-example/prepare.md +++ b/docs/en/md/dev-example/prepare.md @@ -3,13 +3,12 @@ ## Summary Ngbatis provides two ways for developers to access nebula. + - Close to Mybatis-plus, providing a basic `DAO` to be extends, unnecessary to write any `nGQL` to operate single table, include vertex and edge. (See [By Basic DAO](./dao-basic) for more details) - Close to Mybatis, supporting developers to write complex `nGQL` or `Cypher` to finish read or write data. (See [By Custom nGQL](./custom-crud) for more details) - Take `Person` 与 `Like` as examples. - ## Create Schema in Nebula (refer [CREATE TAG](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/10.tag-statements/1.create-tag/)、[CREATE EDGE](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/11.edge-type-statements/1.create-edge/)、[CREATE INDEX](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/14.native-index-statements/1.create-native-index/)) ```sql @@ -33,7 +32,9 @@ CREATE TAG INDEX `i_person_name` on `person`(`name`(50)); ``` ## Necessary `POJO` for two ways' + ### Person.java + ```java package your.domain; @@ -56,6 +57,7 @@ public class Person { ``` ### Like.java + ```java package your.domain; @@ -71,6 +73,7 @@ public class Like { ``` ### LikeWithRank.java + ```java package your.domain; @@ -86,4 +89,4 @@ public class LikeWithRank { } ``` -By now, the 'POJO' used in the two usage examples has been created. Let's start our coding journey. \ No newline at end of file +By now, the 'POJO' used in the two usage examples has been created. Let's start our coding journey. diff --git a/docs/en/md/quick-start/about.md b/docs/en/md/quick-start/about.md index b6da3a1b..d6a3effe 100644 --- a/docs/en/md/quick-start/about.md +++ b/docs/en/md/quick-start/about.md @@ -1,19 +1,23 @@ -[![LOGO](./light.png)](https://github.com/nebula-contrib/ngbatis) +<a href="https://github.com/nebula-contrib/ngbatis"><img src="./light.png" alt="LOGO"></a> + # About Ngbatis ## How to position ngbatis + **NGBATIS** is a database ORM framework base [Nebula Graph](https://github.com/vesoft-inc/nebula) + springboot. Take advantage of [mybatis'](https://github.com/mybatis/mybatis-3) usage habits to develop. Including some frequently-used operation in single table and vertex-edge, like [mybatis-plus](https://github.com/baomidou/mybatis-plus). If you prefer JPA, [graph-ocean](https://github.com/nebula-contrib/graph-ocean) is a good choice. > If you don't have your own Nebula Graph Database, please arrange it for yourself. [Lucky Gate](https://docs.nebula-graph.com.cn/3.2.0/4.deployment-and-installation/2.compile-and-install-nebula-graph/3.deploy-nebula-graph-with-docker-compose/) ## Relevant technologies of key steps + - Database:[Nebula Graph](https://github.com/vesoft-inc/nebula) - Dynamic Proxy Framework:[ASM](https://gitlab.ow2.org/asm/asm/) `v8.0` - Mapper file parser:[jsoup](https://github.com/jhy/jsoup) `v1.12.1` - nGQL Template:[Beetl](https://github.com/javamonkey/beetl2.0) `v3.1.8.RELEASE` ## Environmental requirements + - Java 8+ -- Springboot \ No newline at end of file +- Springboot diff --git a/docs/en/md/quick-start/install.md b/docs/en/md/quick-start/install.md index 94c0febd..110b328c 100644 --- a/docs/en/md/quick-start/install.md +++ b/docs/en/md/quick-start/install.md @@ -1,6 +1,7 @@ # Import and Config -## Adding in `pom.xml`: +## Adding in `pom.xml` + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -10,6 +11,7 @@ ``` ## Adding data source configuration in `application.yml` + ```yml nebula: hosts: 127.0.0.1:19669, ip:port, .... @@ -28,27 +30,31 @@ nebula: ``` ## Import ngbatis bean + ### Nebula only, in your project + ```java @SpringBootApplication( exclude={ DataSourceAutoConfiguration.class }, scanBasePackages = { "your.domain", "org.nebula.contrib" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` + ### Multi database including Nebula + ```java @SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` @@ -56,6 +62,7 @@ public class YourSpringbootApplication { ### Primary key generator #### Declare primary key generator + ```java import org.nebula.contrib.ngbatis.PkGenerator; @@ -71,6 +78,7 @@ public class CustomPkGenerator implements PkGenerator { ``` #### Register primary key generator as bean + ```java @Configuration public class PkGeneratorConfig { diff --git a/docs/en/md/step-forward-docs/advanced-configuration.md b/docs/en/md/step-forward-docs/advanced-configuration.md index b934a937..7eb450e7 100644 --- a/docs/en/md/step-forward-docs/advanced-configuration.md +++ b/docs/en/md/step-forward-docs/advanced-configuration.md @@ -1,5 +1,8 @@ + # Advanced Configuration + ## How to display SQL on the console + ```yml logging: level: @@ -7,6 +10,7 @@ logging: ``` ## How to change location of XXXDao.xml + ```yml cql: parser: @@ -15,6 +19,7 @@ cql: ``` ## How to modify the statement of the NebulaBasicDao + ```yml cql: parser: @@ -24,10 +29,11 @@ cql: ``` ## When writing statements in XML, what if `if` and `for` are involved and @if / @for is not preferred + ```yaml cql: parser: # If you are not used to using @if or @for in the template, you can replace the delimiter by yourself statement-start: <% # default: @ statement-end: %> # default: null -``` \ No newline at end of file +``` diff --git a/docs/en/md/step-forward-docs/operation-sequence.md b/docs/en/md/step-forward-docs/operation-sequence.md index 9907a514..d2847ccf 100644 --- a/docs/en/md/step-forward-docs/operation-sequence.md +++ b/docs/en/md/step-forward-docs/operation-sequence.md @@ -1,4 +1,78 @@ -# Operatior Sequence +<!-- +Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved. + +This source code is licensed under Apache 2.0 License. +--> + +# Detailed Description of the Framework Execution Process + +## Initialization + +1. Scanned by Spring Boot for initialization. The entry point is configured in: [spring.factories](./src/main/resources/META-INF/spring.factories). +2. The starting class is: [NgbatisContextInitialize](src/main/java/org/nebula/contrib/ngbatis/NgbatisContextInitializer.java). +3. Initialization process: + 1. Read NebulaPoolConfig connection information from the Spring Boot configuration file. + 2. Create a global context: [MapperContext](src/main/java/org/nebula/contrib/ngbatis/models/MapperContext.java). + 3. Read and parse templates for NebulaDaoBasic, storing them in the context. Performed by: [DaoResourceLoader](./src/main/java/org/nebula/contrib/ngbatis/io/DaoResourceLoader.java). + 1. Read files specified by cql.parser.mapper-tpl-location. + 2. Use JSoup for XML parsing (method names, nGQL templates). + 4. Read and parse user-created XXXDao.xml files, storing them in the context. Performed by: [MapperResourceLoader](./src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java). + 1. Read all XML files specified by cql.parser.mapper-locations. + 2. Use JSoup to parse each file. + 1. Parse XML files, retrieve corresponding interfaces and create a class model: [ClassModel](./src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java). + 2. Parse subtags, retrieve specific methods, and create a method model: [MethodModel](./src/main/java/org/nebula/contrib/ngbatis/models/MethodModel.java). + 5. Create NebulaPool and store it in the context. + 6. Establish the relationship between explicit entity types and database types (MapperContext.tagTypeMapping). By default, types for the generic T of NebulaDaoBasic are loaded. If NebulaDaoBasic is not used, developers can add their own types. For example, put: key: "person," value: Person.class. + 7. Register XXXDao objects as Spring-managed beans. + 1. Generate dynamic proxy classes using ASM based on class model information. These proxy classes exist in memory as bytecode. Performed by: [MapperProxyClassGenerator](./src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxyClassGenerator.java). + 1. Class bytecode + 2. No-argument constructor bytecode + 3. Method bytecode + > The actual method called is MapperProxy.invoke, passing in class and method information along with runtime parameters. The corresponding nGQL is retrieved from the context. See details below in [Runtime]. + 2. Load the proxy class into the JVM. Performed by: [RAMClassLoader](src/main/java/org/nebula/contrib/ngbatis/proxy/RamClassLoader.java). + 3. Retrieve the fully qualified interface names from the class model and register the classes loaded in step 2 as Spring beans managed by the Spring bean container. + 8. Register result set handlers in bulk. The mechanism involves extending the AbstractResultHandler abstract class. When objects are created, they are registered in the context. This mechanism handles different result types inside ResultSets, corresponding to different return values in nGQL. For more details, see [Runtime]. + +> At this point, the initialization process of ngbatis dynamic proxies is complete. + +## Application Configuration, Main Class [Env](src/main/java/org/nebula/contrib/ngbatis/Env.java) + +1. Declare an nGQL parameter parser. The default approach uses the Beetl template engine for parsing. [BeetlTextRender](./src/main/java/org/nebula/contrib/ngbatis/binding/BeetlTextRender.java). + > You can implement your own [TextResolver](src/main/java/org/nebula/contrib/ngbatis/TextResolver.java) and manage it with @Primary if you want to use a different text resolver. +2. Specify the primary key generator (vertex id and edge rank value setter). You can use a timestamp-based primary key generator to obtain primary keys, but it is recommended to implement your own key generation strategy based on your application's architecture. + + ```java + @Configuration + public class PkGeneratorConfig { + @Bean + public PkGenerator pkGenerator() { + return new TimestampPkGenerator(); + } + } + ``` + +3. You can further customize result handling for various types by extending [AbstractResultHandler](./src/main/java/org/nebula/contrib/ngbatis/handler/AbstractResultHandler.java). + +## Runtime + +1. Business logic integrates dynamic proxy classes into business classes through dependency injection. +2. Business classes invoke actual methods and pass parameters. +3. Dynamic proxies execute MapperProxy.invoke (interface name, method name, parameter list). + 1. Read interface parameter serializers and serialize interface parameters to match placeholders in XML with key-value pairs. + 2. Replace placeholders in the XML. + 3. Retrieve a session and execute executeWithParameter. + 4. Result handling: Result handlers are routed through [ResultResolver](src/main/java/org/nebula/contrib/ngbatis/ResultResolver.java), with the choice determined by the return value declared in the method model and the declared generic resultType. In this step, the ORM process is completed. + +## Developer Usage Approach (for complex extensions, see [Application Configuration] if there are no specific requirements) + +1. Specify a primary key generator as shown in [Application Configuration.2]. +2. Create XXXDao.java. +3. Create XXXDao.xml and specify the namespace as XXXDao.java. +4. Write nGQL in XXXDao.xml. +5. When calling the business logic, inject XXXDao directly and call the corresponding method to retrieve and execute the nGQL without handling the result set, thus obtaining the required entity objects. + +# Operation Sequence + ## Initialization process at service startup ```mermaid @@ -39,6 +113,7 @@ sequenceDiagram ``` ## When the proxy method is called + ```mermaid sequenceDiagram XXXDao->>MapperProxy: invoke( namespace, methodName, args ) @@ -58,4 +133,3 @@ sequenceDiagram MapperProxy_invoke->>MapperProxy: MapperProxy->> XXXDao: The result corresponding to the XML return value type ``` - diff --git a/docs/zhCn/md/dev-example/built-in-function.md b/docs/zhCn/md/dev-example/built-in-function.md index 41115605..4995e416 100644 --- a/docs/zhCn/md/dev-example/built-in-function.md +++ b/docs/zhCn/md/dev-example/built-in-function.md @@ -1,6 +1,7 @@ # Ngbatis内置函数与变量 ## 如何使用内置函数与变量 + ```java package your.domain; @@ -8,6 +9,7 @@ public interface PersonDao { void insertPerson( Person person ); } ``` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -25,24 +27,24 @@ public interface PersonDao { </mapper> ``` + > 此出用到了 `ng.kv`、`ng.id`、`ng.tagName`、`ng.join`、`ng.schemaFmt`等内置函数,用到了`ng_args`内置参数。 > 了解了使用的地方之后,咱们在往下的内容中,将对函数进一步介绍。 - ## 内置变量 + - ng_cm ClassModel Dao接口的类模型,便于在xml中拿到更多类信息 (1.1.0-rc) - ng_mm MethodModel Dao接口中某个方法的模型,便于在xml中拿到方法信息,包括入参类型。(1.1.0-rc) - ng_args 传入Dao接口的原始参数,未序列化前。(1.1.0-rc) ## 内置函数 - - ng.valueFmt > 对不定类型的数据值进行格式化,忽略是否追加单引号及日期格式化,直接传原始 java类型即可 参数位 | 参数说明 | 类型 | 是否必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y | + 1 | 值 | Object | Y | 2 | 如果是字符串是否在前后追加 .* 形成模糊查询 | boolean | N | false > 自 v1.1.2 起,默认对字符串类型进行转义,可使用:`ValueFmtFn.setEscape( false )` 进行关闭 @@ -58,17 +60,15 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 与Schema对应的实体类对象 | Object | Y + 1 | 与Schema对应的实体类对象 | Object | Y 2 | 类模型,使用 `ng_cm` 传入 | ClassModel | N | null - - - ng.pkField > 用于获取 主键属性,java.lang.reflect.Field 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类类型 | Class<?> | Y + 1 | 实体类类型 | Class<?> | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | false - ng.pkName @@ -76,7 +76,7 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.entityType @@ -85,14 +85,14 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y - ng.fieldNames > 获取属性名集合(不包括主键) 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | true 时使用列名,false 时使用属性名 | Boolean | N | true - ng.id @@ -100,12 +100,13 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 如果不存在主键是否报错中断 | Boolean | N | true 3 | 如果值为空,true会通过主键生成器返回新值,false 时 返回空 | Boolean | N | true - ng.kv > 通过实体对象或者获取多个集合 + > > - columns 列名集合 > - valueNames 属性名集合 > - values 值集合 @@ -113,7 +114,7 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 实体类对象 | Object | Y + 1 | 实体类对象 | Object | Y 2 | 参数名前缀 | String | N | null 3 | 是否排除主键 | Boolean | N | true 4 | 是否排除空值 | Boolean | N | true @@ -124,18 +125,23 @@ public interface PersonDao { 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 待格式化的集合 | Iterable | Y - 2 | 元素间的分隔符 | String | N | `,` + 1 | 待格式化的集合 | Iterable | Y + 2 | 元素间的分隔符 | String | N | `,` 3 | 函数名,各元素拼接前,可进行函数名指定的格式化函数先行格式化,再拼接 | String | N | null - - ng.ifStringLike > 类型为字符串时,前后拼接 `.*` 参数位 | 参数说明 | 类型 | 必传 | 默认值 ---|---|---|---|--- - 1 | 值 | Object | Y + 1 | 值 | Object | Y 2 | 属性类型 | Object | N | null 3 | 属性名,用于不将值明文写在 ngql 中,而使用参数名,让 nebula 在参数中取值 | String | N | null +- ng.include + > 引用nGQL片段 + 参数位 | 参数说明 | 类型 | 必传 | 默认值 + ---|-------------------------------------------------------------------------------------------|---------|---|--- + 1 | 要引用的nGQL片段ID.<br/>引用其他mapper的nGQL片段,片段ID前需要加上片段所在的namespace,例:your.domain.TestDao.nGQL-ID | String | Y + 2 | 引用nGQL片段时额外的参数,在生成语句时优先使用额外参数 | Object | N | null diff --git a/docs/zhCn/md/dev-example/custom-crud.md b/docs/zhCn/md/dev-example/custom-crud.md index 87fca652..63f5e69b 100644 --- a/docs/zhCn/md/dev-example/custom-crud.md +++ b/docs/zhCn/md/dev-example/custom-crud.md @@ -2,9 +2,11 @@ - > 使用此方式的时候,对 nGQL、cypher 的熟悉度要求会高一些。还不太熟悉的开发者,可以通过【[什么是nGQL](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/1.nGQL-overview/1.overview/)】进行了解。 - > 另外提一下:这边使用的模板引擎是Beetl - > - [Beetl官方文档](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947),主要看占位符。ngbatis已经做好了变量设置,如果只是参数填充,可以忽略定界符的使用。 + > + > - [Beetl官方文档](https://www.kancloud.cn/xiandafu/beetl3_guide/2138947),主要看占位符。ngbatis已经做好了变量设置,如果只是参数填充,可以忽略定界符的使用。 【例子详见[如何传入参数](./parameter-use)】 但,参数条件控制跟参数循环定界符几乎不可避免。因`ngbatis`关于`beetl`配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @ \n,如: +> > ```diff > - <%if ( aBool ) { > - @@ -13,16 +15,18 @@ > + > + @} > ``` - > - [Beetl文档-用于处理参数的函数](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) +> + > - [Beetl文档-用于处理参数的函数](https://www.kancloud.cn/xiandafu/beetl3_guide/2138956) > - [Beetl文档-条件控制](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)【例子详见[参数条件控制](./parameter-if)】 > - [Beetl文档-循环语句](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)【例子详见[参数遍历](./parameter-for)】 > - [Beetl在线测试小工具](http://ibeetl.com/beetlonline/) - 与[使用基类读写](./dao-basic)相同,需要编写一个 XXXDao.java 文件与 XXXDao.xml 文件。 ## 新建文件 + ### 创建一个Person对应的Dao,如果不需要用到基类方法,可以不继承 NebulaDaoBasic + ```java package your.domain; @@ -34,26 +38,32 @@ public interface PersonDao { ``` ### 创建一个名为 PersonDao.xml 的文件,默认位置为:`/resources/mapper` + ```xml <!-- 如果 space 与 yml 中声明的一致,可不写 --> <mapper namespace="your.domain.PersonDao" space="test"> </mapper> ``` + > XXXDao.java 无需经过 @Mapper 或者 @Component 进行注解,而是通过 namespace 进行发现,并自动注册成 Bean。 > 前提是:namespace 需要在 @SpringBootApplication 注解下的 scanBasePackages 值中。 > 如:@SpringBootApplication( scanBasePackages = { "your.domain", "org.nebula.contrib" } ) ## 如何让 java 程序通过 ngbatis 执行 nGQL | cypher -### 以一个简单的查询语句为例: +### 以一个简单的查询语句为例 + #### 在 PersonDao.java 中追加接口 + ```java Integer select1(); ``` + > 目前版本中,接口的返回值类型与方法参数类型,如果是基本类型,仅支持包装类,如 int 请写成 Integer。 #### 在 PersonDao.xml 中新增一个标签 + ```xml <!-- 如果 space 与 yml 中声明的或 mapper 的 space 一致,可不写 --> <select id="select1" space="test"> @@ -61,4 +71,61 @@ public interface PersonDao { </select> ``` -> Integer result = personDao.select1(); // result : 1 \ No newline at end of file +> Integer result = personDao.select1(); // result : 1 + +## 引用一个nGQL片段 +> +> 像MyBatis的include标签一样引用一段语句。 + +NgBatis使用内置函数`ng.include`实现引用,`ng.include`的说明可见[Ngbatis内置函数与变量](./built-in-function) + +### 定义Dao接口 + +```java +package your.domain; + +import org.springframework.data.repository.query.Param; +import ye.weicheng.ngbatis.demo.pojo.Person + +public interface TestDao { + + Integer returnMyInt(@Param("myInt") Integer myInt); + + Integer returnAge(@Param("person") Person person); + +} +``` + +### 编写对应的xml文件,并定义nGQL片段和接口方法语句 + +```xml + <!-- 如果 space 与 yml 中声明的一致,可不写 --> + <mapper namespace="your.domain.TestDao" space="test"> + + <!-- 在xml文件 mapper 节点下任意位置定义nGQL片段 --> + <nGQL id="my-ngql-id"> + ${myInt} + </nGQL> + + <!-- 定义接口方法语句 --> + <select id="returnMyInt" resultType="java.lang.Integer"> + RETURN @ng.include('my-ngql-id'); + </select> + + <!-- nGQL片段额外参数例子 --> + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('my-ngql-id',{'myInt':age}); + </nGQL> + + </mapper> +``` + +nGQL片段自动继承Dao方法所传入的参数,可以在nGQL片段内直接使用,也可以在`ng.include`函数上指定额外参数,在生成语句时优先使用额外参数,参考上方例子。 + +nGQL片段不限层级,nGQL片段也可以引用nGQL片段,考虑到性能,不建议过多层级的nGQL语句引用。 + +如果需要引用其他mapper内的nGQL片段,使用`ng.include`函数时需要在片段ID前面拼接上片段所在的namespace,如:`@ng.include('your.domain.XxxDao.nGQL-ID');` diff --git a/docs/zhCn/md/dev-example/dao-basic.md b/docs/zhCn/md/dev-example/dao-basic.md index 64f880d7..74462b44 100644 --- a/docs/zhCn/md/dev-example/dao-basic.md +++ b/docs/zhCn/md/dev-example/dao-basic.md @@ -1,6 +1,7 @@ # 使用基类读写 ## 创建一个Person对应的Dao,并继承 NebulaDaoBasic + ```java package your.domain; @@ -12,6 +13,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## 创建一个名为 PersonDao.xml 的文件,默认位置为:`/resources/mapper` + ```xml <mapper namespace="your.domain.PersonDao"> @@ -19,6 +21,7 @@ public interface PersonDao extends NebulaDaoBasic<Person, String> { ``` ## 在 Service 层中举例 + ```java @Service diff --git a/docs/zhCn/md/dev-example/multi-tag.md b/docs/zhCn/md/dev-example/multi-tag.md index 31db9927..a0f3d618 100644 --- a/docs/zhCn/md/dev-example/multi-tag.md +++ b/docs/zhCn/md/dev-example/multi-tag.md @@ -1,10 +1,12 @@ # 基类实现多标签 ^v1.1.2 ## 实现的效果 + - insert时可以一次同时将 Person 和 Employee 的属性写入数据库 - select时可以一次同时将 Person 和 Employee 的属性读出,但如果该节点具备其他标签,则不会读出 ## 实体类 + ```java @Data @Table(name = "employee") @@ -16,6 +18,7 @@ public class Employee extends Person { > DAO的实现方式与单标签的实现方式一致 ## DAO + ```java import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; @@ -26,8 +29,9 @@ public interface EmployeeDao extends NebulaDaoBasic<Employee, String> { ``` ## DAO XML + ```xml <mapper namespace="your.domain.repository.EmployeeDao"> </mapper> -``` \ No newline at end of file +``` diff --git a/docs/zhCn/md/dev-example/parameter-for.md b/docs/zhCn/md/dev-example/parameter-for.md index f156df3a..1accbea8 100644 --- a/docs/zhCn/md/dev-example/parameter-for.md +++ b/docs/zhCn/md/dev-example/parameter-for.md @@ -2,6 +2,7 @@ > 遍历的部分跟 mybatis 的差异比较大,使用了 Beetl 的遍历语法。具体可参考官方文档【[1.10 循环语句](https://www.kancloud.cn/xiandafu/beetl3_guide/2138952)】 > 因配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @ \n,如: + ```diff - <%for ( item in list ) { - @@ -12,7 +13,9 @@ ``` ## 对Map的遍历,可用于动态查询 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param // person: { "name": "张三", "gender": "F" } @@ -20,6 +23,7 @@ ``` - PersonDao.xml + ```xml <select id="selectByPerson"> MATCH (n: person) @@ -37,6 +41,7 @@ ## 对 List 遍历,可用于批处理 - PersonDao.java + ```java // org.springframework.data.repository.query.Param // personList: [{"gender":"F","name":"张三"},{"gender":"M","name":"王五"},{"gender":"F","name":"赵六"}] @@ -44,11 +49,13 @@ ``` - 参数为: + ```json :param personList => [{"gender":"F","name":"张三"},{"gender":"M","name":"王五"},{"gender":"F","name":"赵六"}] ``` - PersonDao.xml + ```xml <insert id="insertPersonList"> @for ( p in personList ) { @@ -58,6 +65,7 @@ ``` - 执行的语句为: + ```sql INSERT VERTEX `person` ( name, gender ) VALUES '张三' : ( '张三', 'F' ); INSERT VERTEX `person` ( name, gender ) VALUES '王五' : ( '王五', 'M' ); diff --git a/docs/zhCn/md/dev-example/parameter-if.md b/docs/zhCn/md/dev-example/parameter-if.md index 3899bd19..b960dfe8 100644 --- a/docs/zhCn/md/dev-example/parameter-if.md +++ b/docs/zhCn/md/dev-example/parameter-if.md @@ -2,6 +2,7 @@ > 语法参考【[Beetl 条件控制](https://www.kancloud.cn/xiandafu/beetl3_guide/2138953)】 > 因配置的差异,文档中如涉及界定符,则由文档中的 <% %> 替换成 @,如: + ```diff - <%if ( aBool ) { - @@ -12,12 +13,15 @@ ``` ## 三元表达式的使用 + - PersonDao.java + ```java Person selectByNameIfNotEmpty( String name ); ``` - PersonDao.xml + ```xml <select id="selectByNameIfNotEmpty"> MATCH (n: person) @@ -29,12 +33,16 @@ ``` ## if 的使用 + - PersonDao.java + ```java // params = { age: 18 } Person selectByNameAndAge( Person person, Map<String, Object> params ); ``` + - PersonDao.xml + ```xml <select id="selectByNameAndAge"> MATCH (n: person) @@ -49,14 +57,18 @@ LIMIT 1 </select> ``` + ## if-else 的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -72,13 +84,16 @@ ``` ## switch case的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -97,16 +112,20 @@ LIMIT 1 </select> ``` + - > **注意**: 此处放入 switch 的变量,不可为 null ## select case 的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByGender( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -122,15 +141,17 @@ </select> ``` - ## decode 函数的使用 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectMarriageable( @Param("gender") String gender ); ``` - PersonDao.xml + ```xml <select id="selectMarriageable"> MATCH (n: person) @@ -144,5 +165,7 @@ LIMIT 1 </select> ``` + ## 总结 -到此,可用于条件判断的方式基本介绍完成。只能用于入参时的判断。返回值不能使用条件控制。 \ No newline at end of file + +到此,可用于条件判断的方式基本介绍完成。只能用于入参时的判断。返回值不能使用条件控制。 diff --git a/docs/zhCn/md/dev-example/parameter-use.md b/docs/zhCn/md/dev-example/parameter-use.md index fc706581..6f20871f 100644 --- a/docs/zhCn/md/dev-example/parameter-use.md +++ b/docs/zhCn/md/dev-example/parameter-use.md @@ -4,17 +4,21 @@ 接下来,将在当前部分介绍如何对自己编写的语句进行传参。 > **注意**:所有参数基本类型目前只支持包装类,如 int 需要写成 Integer。 - ## 在 `nGQL | cypher` 中读取参数 ## 具名参数 +> > 参数被 @Param 所注解。org.springframework.data.repository.query.Param +> #### 简单类型 + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("name") String param ); ``` + - PersonDao.xml ::: code-group @@ -27,6 +31,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -44,14 +49,18 @@ LIMIT 1 </select> ``` + ::: #### POJO 或 Map + - PersonDao.java + ```java // org.springframework.data.repository.query.Param Person selectByName( @Param("person") Person person ); ``` + - PersonDao.xml ::: code-group @@ -63,6 +72,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -80,16 +90,20 @@ LIMIT 1 </select> ``` + ::: + > 参数读取支持 `.` 运算符,如果是 POJO 或 Map,可以直接读取内部属性 ## 匿名参数 + - 如果在接口中声明的参数中,不带 @Param 注解,则使用下标位进行获取,即 ${ p0 }、${ p1 }、${ p2 }、${ p3 } ... 或 $p0、$p1、$p2、$p3 ... - 参数列表长度为1,类型为 POJO 或 Map 时,可直接读取属性 - #### 基本类型 + - PersonDao.java + ```java Person selectByName( String name ); ``` @@ -105,6 +119,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -113,6 +128,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -123,12 +139,17 @@ ``` ::: + #### POJO 或 Map -##### 参数只有一个时: + +##### 参数只有一个时 + - PersonDao.java + ```java Person selectByName( Person person ); ``` + - PersonDao.xml ::: code-group @@ -140,6 +161,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -148,6 +170,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -156,14 +179,18 @@ LIMIT 1 </select> ``` + ::: -##### 参数有两个及以上时: +##### 参数有两个及以上时 + - PersonDao.java + ```java // params = { age: 18 } Person selectByName( Person person, Map<String, Object> params ); ``` + - PersonDao.xml ::: code-group @@ -176,6 +203,7 @@ LIMIT 1 </select> ``` + ```xml [方式2] <select id="selectByName"> MATCH (n: person) @@ -185,6 +213,7 @@ LIMIT 1 </select> ``` + ```xml [参数由 DB 替换] <select id="selectByName"> MATCH (n: person) @@ -194,17 +223,23 @@ LIMIT 1 </select> ``` + ::: -## 集合类型的参数获取,与基本类型一致。 +## 集合类型的参数获取,与基本类型一致 + - 匿名时,使用 ${ p0 }、${ p1 },或 $p0、$p1... - 具名时,直接使用注解内的参数名 - 如果是基本类型的集合,不需要做复杂处理,可以直接传入 + --- + - PersonDao.java + ```java List<Person> findByIds( List<String> names ); ``` + - PersonDao.xml ::: code-group @@ -215,6 +250,7 @@ RETURN n </select> ``` + ```xml [方式2] <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -222,6 +258,7 @@ RETURN n </select> ``` + ```xml [参数由 DB 替换] <select id="findByIds" resultType="your.domain.Person"> MATCH (n: person) @@ -232,13 +269,14 @@ ::: - ## 常见问题 + - 两种占位符格式: - - `${ 参数名.子参数名 }` ngbatis 的占位符,执行到数据库前完成替换 - - `$参数名.子参数名` NebulaGraph 的占位符,由数据库完成替换,但需要注意支持参数化的位置。 + - `${ 参数名.子参数名 }` ngbatis 的占位符,执行到数据库前完成替换 + - `$参数名.子参数名` NebulaGraph 的占位符,由数据库完成替换,但需要注意支持参数化的位置。 - 特殊符号问题: - - 可以使用内置函数进行转义 `${ ng.valueFmt( 参数名 ) }`,该函数同样无需判断数据类型。如是字符串也无需加前后引号 + - 可以使用内置函数进行转义 `${ ng.valueFmt( 参数名 ) }`,该函数同样无需判断数据类型。如是字符串也无需加前后引号 ## 总结 + 到此,关于参数获取的大致介绍完毕。如果有关于获取参数后的条件控制以及遍历的需求,请移步【[参数条件控制](./parameter-if)】、【[参数遍历](./parameter-for)】 diff --git a/docs/zhCn/md/dev-example/prepare.md b/docs/zhCn/md/dev-example/prepare.md index 99304679..7d251078 100644 --- a/docs/zhCn/md/dev-example/prepare.md +++ b/docs/zhCn/md/dev-example/prepare.md @@ -1,13 +1,13 @@ # 准备工作 ## 大致介绍 + Ngbatis 提供了两种方式为开发者提供便利 + - 类似于 Mybatis-plus 的方式,提供一个基类让业务的`DAO`进行继承,不需要自己写 `nGQL` 就能完成单顶点、单边的增删改查。 (详见[使用基类编写](./dao-basic)) - 类似于 Mybatis 的方式,支持自己编写复杂的 `nGQL` 或 `Cypher` 来完成复杂的业务查询与数据写入。(详见[自定义nGQL](./custom-crud)) - - 下面,以 `Person` 与 `Like` 为例。 ## Nebula Graph 中创建的 Schema (参考[CREATE TAG](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/10.tag-statements/1.create-tag/)、[CREATE EDGE](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/11.edge-type-statements/1.create-edge/)、[CREATE INDEX](https://docs.nebula-graph.com.cn/3.1.0/3.ngql-guide/14.native-index-statements/1.create-native-index/)) @@ -32,7 +32,9 @@ CREATE TAG INDEX `i_person_name` on `person`(`name`(50)); ``` ## 两种方式都需要的 `POJO` 类 + ### Person.java + ```java package your.domain; @@ -61,6 +63,7 @@ public class Person { ``` ### Like.java + ```java package your.domain; @@ -76,6 +79,7 @@ public class Like { ``` ### LikeWithRank.java + ```java package your.domain; @@ -91,4 +95,4 @@ public class LikeWithRank { } ``` -到此,两种使用方式样例所用的 `POJO` 就已经创建完毕。接下来开始我们的介绍。 \ No newline at end of file +到此,两种使用方式样例所用的 `POJO` 就已经创建完毕。接下来开始我们的介绍。 diff --git a/docs/zhCn/md/dev-example/result-built-in.md b/docs/zhCn/md/dev-example/result-built-in.md index ceafb621..eab15c7c 100644 --- a/docs/zhCn/md/dev-example/result-built-in.md +++ b/docs/zhCn/md/dev-example/result-built-in.md @@ -2,8 +2,8 @@ 如果项目中不建立实体,都是动态查询的话,可以考虑使用内置的返回值类型。数据结构如下: - ## NgVertex + ```json { "properties":{ // Map, key 是 tag 名称,keys 的长度与本级的 tags 的长度一致 @@ -20,6 +20,7 @@ ``` ## NgEdge + ```json { "dstID":"1670225547548", @@ -33,6 +34,7 @@ ``` ## NgSubgraph + ```json { "edges":[ @@ -60,4 +62,4 @@ } ] } -``` \ No newline at end of file +``` diff --git a/docs/zhCn/md/dev-example/result.md b/docs/zhCn/md/dev-example/result.md index 6a3ca003..d48c94f8 100644 --- a/docs/zhCn/md/dev-example/result.md +++ b/docs/zhCn/md/dev-example/result.md @@ -1,28 +1,41 @@ # 不同返回值类型 + 从nebula获得结果后,往往并不能获得业务所需的结果类型,此时,开发者需要告知 ngbatis 具体业务所需的类型。 ## 原始类型 [ResultSet](https://github.com/vesoft-inc/nebula-java/blob/master/client/src/main/java/com/vesoft/nebula/client/graph/data/ResultSet.java) (com.vesoft.nebula.client.graph.data.ResultSet) + 如果接口返回值为 nebula 的 ResultSet,ngbatis 不做任何处理,直接返回跟调用方,由开发者在调用方中自行处理结果集。 + - PersonDao.java + ```java ResultSet returnResultSet(); ``` + - PersonDao.xml + ```xml <select id="returnResultSet"> RETURN 'You are best' </select> ``` + - > 如果在下列的几种类型中,不能满足开发所需的结果集处理,可以使用获取原始ResultSet类型的返回值,并自行做灵活处理。可阅读[ResultSet源码](https://github.com/vesoft-inc/nebula-java/blob/master/client/src/main/java/com/vesoft/nebula/client/graph/data/ResultSet.java)做近一步了解。 ## 非集合类型 + 此时,结果类型已经通过 方法的返回值类型告知 ngbatis,所以无需额外的配置,即可完成类型映射。 + ### 基本类型 + - PersonDao.java + ```java String returnString(); ``` + - PersonDao.xml + ```xml <select id="returnString"> RETURN 'You are best' @@ -30,12 +43,16 @@ ``` ### POJO | Map + - PersonDao.java + ```java Person returnFirst(); // 或者 Map returnFirst(); ``` + - PersonDao.xml + ```xml <select id="returnFirst"> MATCH (n: person) @@ -43,7 +60,9 @@ LIMIT 1 </select> ``` + - json序列化后,结果为: + ```json { "name": "张三", @@ -53,17 +72,22 @@ } ``` - ## 集合类型 + 因为运行时,方法在字节码中的集合泛型丢失,因此需要通过标签中的 `resultType` 属性告知 ngbatis,多行中单行结果的类型。 + ### 单栏位返回值 #### 基本类型 + - PersonDao.java + ```java List<String> returnNameTop10(); ``` + - PersonDao.xml + ```xml <select id="returnNameTop10" resultType="java.lang.String"> MATCH (n: person) @@ -71,14 +95,19 @@ LIMIT 10 </select> ``` + - json序列化后,结果为:[ "张三", "李四", ... ] #### POJO + - PersonDao.java + ```java List<Person> returnTop10(); ``` + - PersonDao.xml + ```xml <select id="returnTop10" resultType="your.domain.Person"> MATCH (n: person) @@ -86,7 +115,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -98,14 +129,19 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射到实体类属性 #### Map + - PersonDao.java + ```java List<Map> returnTop10(); ``` + - PersonDao.xml + ```xml <select id="returnTop10" resultType="java.util.Map"> MATCH (n: person) @@ -113,7 +149,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -125,15 +163,21 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射做为 map 的 key ### 多栏位返回值 + #### POJO + - PersonDao.java + ```java List<Person> returnPartTop10(); ``` + - PersonDao.xml + ```xml <select id="returnPartTop10" resultType="your.domain.Person"> MATCH (n: person) @@ -143,7 +187,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -156,13 +202,16 @@ ] ``` - #### Map + - PersonDao.java + ```java List<Map> returnPartTop10(); ``` + - PersonDao.xml + ```xml <select id="returnPartTop10" resultType="java.util.Map"> MATCH (n: person) @@ -172,7 +221,9 @@ LIMIT 10 </select> ``` + - json序列化后,结果为: + ```json [ { @@ -182,12 +233,17 @@ ... ] ``` + > 当返回值栏位只有一个时,读取内部属性映射做为 map 的 key ## 复合对象类型(Path类型处理方式,三元组) + **注意**:下列例子是当前版本处理 Path 结果集的举例 -### 声明复合对象类: - - NRN2.java + +### 声明复合对象类 + +- NRN2.java + ```java package your.domain; @@ -197,12 +253,17 @@ private Person n2; } ``` + ### 非集合类型 - - PersonDao.java + +- PersonDao.java + ```java NRN2 returnFirstRelation(); ``` - - PersonDao.xml + +- PersonDao.xml + ```xml <select id="returnFirst"> MATCH (n: person)-[r: like]->(n2: person) @@ -210,12 +271,17 @@ LIMIT 1 </select> ``` + ### 集合类型 - - PersonDao.java + +- PersonDao.java + ```java List<NRN2> returnRelationTop10(); ``` - - PersonDao.xml + +- PersonDao.xml + ```xml <select id="returnRelationTop10" resultType="your.domain.NRN2"> MATCH (n: person)-[r: like]->(n2: person) @@ -223,4 +289,5 @@ LIMIT 10 </select> ``` - - > 使用 List<Map\> 做为返回值同样奏效,n, r, n2 为 map 的 key + +- > 使用 List<Map\> 做为返回值同样奏效,n, r, n2 为 map 的 key diff --git a/docs/zhCn/md/quick-start/about.md b/docs/zhCn/md/quick-start/about.md index 658f7981..f6ae6ee0 100644 --- a/docs/zhCn/md/quick-start/about.md +++ b/docs/zhCn/md/quick-start/about.md @@ -3,17 +3,20 @@ # 关于 Ngbatis ## 应用程序中的定位 + **NGBATIS** 是一款针对 [Nebula Graph](https://github.com/vesoft-inc/nebula) + Springboot 的数据库 ORM 框架。借鉴于 [MyBatis](https://github.com/mybatis/mybatis-3) 的使用习惯进行开发。包含了一些类似于[mybatis-plus](https://github.com/baomidou/mybatis-plus)的单表操作,另外还有一些图特有的实体-关系基本操作。 如果使用上更习惯于JPA的方式,[graph-ocean](https://github.com/nebula-contrib/graph-ocean) 是个不错的选择。 > 如果你还没有属于自己的 Nebula 图数据库,请给自己安排上。[安装传送门](https://docs.nebula-graph.com.cn/3.2.0/4.deployment-and-installation/2.compile-and-install-nebula-graph/3.deploy-nebula-graph-with-docker-compose/) ## 关键环节的相关技术 + - 数据库:[Nebula Graph](https://github.com/vesoft-inc/nebula) - 动态代理生成框架:[ASM](https://gitlab.ow2.org/asm/asm/) `v8.0` - mapper文件解析:[jsoup](https://github.com/jhy/jsoup) `v1.12.1` - nGQL模板:[Beetl](https://github.com/javamonkey/beetl2.0) `v3.1.8.RELEASE` ## 环境要求 + - Java 8+ -- Springboot \ No newline at end of file +- Springboot diff --git a/docs/zhCn/md/quick-start/features.md b/docs/zhCn/md/quick-start/features.md index a3a2971c..10de31bc 100644 --- a/docs/zhCn/md/quick-start/features.md +++ b/docs/zhCn/md/quick-start/features.md @@ -1,9 +1,11 @@ # 框架特性 ## 一、集成 + - [x] 支持通过简单配置,快速完成 Nebula Graph 与 Springboot 的整合 ## 二、单表(Vertex、Edge)操作,无需写 `nGQL | cypher` +> > 用法参见【[使用基类编写](../dev-example/dao-basic)】 API | 用法说明 @@ -12,7 +14,7 @@ selectById(ID id) | 通过主键获取节点 selectByIds(Collection<I\> ids) | 根据 id 集合获取节点 selectBySelective(T entity) | 按实体属性值查询 selectIdBySelectiveStringLike(T entity) | 根据实体属性值查询,字符串属性使用模糊查询 -selectByMap(Map<String, Object\> param) | 根据 map 参数查询 +selectByMap(Map<String, Object\> param) | 根据 map 参数查询 countByMap(Map<String, Object\> param) | 根据 map 参数统计条数 selectPage(Page<T\> page) | 分页查询 insert(T entity) | 插入 Vertex,空值覆盖 @@ -30,33 +32,35 @@ listStartNodes(Class<E\> startType, Class edgeType, ID endId) | 查找一个节 startNode(Class edgeType, ID endId) | 查找一个节点中,某种关系的唯一一个上游节点 startNode(Class<E\> startType, Class edgeType, ID endId) | 查找查找一个节点特定类型的上游节点 - - ## 三、使用 xml 的方式,集中管理 `nGQL | cypher` +> > 用法参见【[自定义nGQL](../dev-example/custom-crud)】 扫描指定资源包,并获得 `nGQL | cypher` 模板,在模板的基础上做操作。 ### (一) 参数替换 + - [x] 使用占位符为 `nGQL | cypher` 替换参数,并执行到数据库; - 编写查询脚本模板,搭配参数控制,实现动态查询 - 通过参数循环,实现批量操作 ### (二) 通过 Dao 接口的方法签名信息,对 ResultSet 进行处理,形成业务所需类型 - - [x] 集合类型 - - Collection<基本类型> - - Collection<对象类型> `Object类型参考下述Object的支持` - - [x] 基本类型 - - String - - Boolean - - Number (Integer、Long、Float、Double、Byte、Short)。**暂时只支持包装类** - - [x] 对象类型 - - Object - - 多列return值转换成 Map - - 多列return值转换成 POJO - - 支持Vertex类型转换成 POJO - - 支持Edge类型转换成 POJO - - [x] ResultSet 如不需要使用框架自带的结果处理,可直接在接口声明返回值 ResultSet 并自行处理 + +- [x] 集合类型 + - Collection<基本类型> + - Collection<对象类型> `Object类型参考下述Object的支持` +- [x] 基本类型 + - String + - Boolean + - Number (Integer、Long、Float、Double、Byte、Short)。**暂时只支持包装类** +- [x] 对象类型 + - Object + - 多列return值转换成 Map + - 多列return值转换成 POJO + - 支持Vertex类型转换成 POJO + - 支持Edge类型转换成 POJO +- [x] ResultSet 如不需要使用框架自带的结果处理,可直接在接口声明返回值 ResultSet 并自行处理 ## 四、主键生成策略接口 + - [x] 提供主键生成器的埋点,开发者可自定义主键生成器。 diff --git a/docs/zhCn/md/quick-start/install.md b/docs/zhCn/md/quick-start/install.md index 0672ce49..d3fda09a 100644 --- a/docs/zhCn/md/quick-start/install.md +++ b/docs/zhCn/md/quick-start/install.md @@ -1,5 +1,7 @@ # 安装与使用 -## 在 `pom.xml` 中添加: + +## 在 `pom.xml` 中添加 + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -9,6 +11,7 @@ ``` ### SNAPSHOT 版本 + ```xml <dependency> <groupId>org.nebula-contrib</groupId> @@ -16,22 +19,24 @@ <version>1.2.0-SNAPSHOT</version> </dependency> ``` + ```xml - <repositories> - <repository> - <snapshots> - <enabled>true</enabled> - <updatePolicy>always</updatePolicy> - <checksumPolicy>warn</checksumPolicy> - </snapshots> - <id>ossrh</id> - <name>Nexus Snapshot Repository</name> - <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url> - </repository> - </repositories> + <repositories> + <repository> + <snapshots> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + <checksumPolicy>warn</checksumPolicy> + </snapshots> + <id>ossrh</id> + <name>Nexus Snapshot Repository</name> + <url>https://s01.oss.sonatype.org/content/repositories/snapshots</url> + </repository> + </repositories> ``` -## 在 `application.yml` 配置数据源 +## 在 `application.yml` 配置数据源 + ```yml nebula: ngbatis: @@ -58,27 +63,31 @@ nebula: ``` ## 引入 ngbatis bean + ### 项目中,只用到的 Nebula Graph 数据库 + ```java @SpringBootApplication( exclude={ DataSourceAutoConfiguration.class }, scanBasePackages = { "org.nebula.contrib", "your.domain" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` + ### 项目中还有其他数据库 + ```java @SpringBootApplication( scanBasePackages = { "org.nebula.contrib", "your.domain" } ) public class YourSpringbootApplication { - public static void main(String[] args) { - new SpringApplication(YourSpringbootApplication.class).run(args); - } + public static void main(String[] args) { + new SpringApplication(YourSpringbootApplication.class).run(args); + } } ``` @@ -86,6 +95,7 @@ public class YourSpringbootApplication { ## 主键生成器 #### 创建并注册主键生成器 + ```java import org.nebula.contrib.ngbatis.PkGenerator; diff --git a/docs/zhCn/md/step-forward-docs/advanced-configuration.md b/docs/zhCn/md/step-forward-docs/advanced-configuration.md index 98df72c4..2b7f2920 100644 --- a/docs/zhCn/md/step-forward-docs/advanced-configuration.md +++ b/docs/zhCn/md/step-forward-docs/advanced-configuration.md @@ -1,6 +1,8 @@ # 进阶配置 -## 如何在控制台打印 sql + +## 如何在控制台打印 sql + ```yml logging: level: @@ -8,6 +10,7 @@ logging: ``` ## 如何更改 XXXDao.xml 的位置 + ```yml cql: parser: @@ -16,6 +19,7 @@ cql: ``` ## 如何修改基类的语句 + ```yml cql: parser: @@ -27,6 +31,7 @@ cql: ``` ## 在 xml 写语句时,如果涉及 if 跟 for,又不喜欢用 @if / @for 怎么办 + ```yml cql: parser: diff --git a/docs/zhCn/md/step-forward-docs/operation-sequence.md b/docs/zhCn/md/step-forward-docs/operation-sequence.md index e13fc301..1c081b4d 100644 --- a/docs/zhCn/md/step-forward-docs/operation-sequence.md +++ b/docs/zhCn/md/step-forward-docs/operation-sequence.md @@ -1,4 +1,5 @@ # 运行时序 + ## 服务启动时的初始化过程 ```mermaid @@ -39,6 +40,7 @@ sequenceDiagram ``` ## 当代理方法被调用时 + ```mermaid sequenceDiagram XXXDao->>MapperProxy: invoke( 接口名, 方法名, 参数列表 ) diff --git a/googl_codestyle.xml b/google_codestyle.xml similarity index 100% rename from googl_codestyle.xml rename to google_codestyle.xml diff --git a/ngbatis-demo/pom.xml b/ngbatis-demo/pom.xml index f55e8573..3a66086b 100644 --- a/ngbatis-demo/pom.xml +++ b/ngbatis-demo/pom.xml @@ -14,7 +14,7 @@ <name>ngbatis-demo</name> <description>Demo project for Spring Boot</description> <properties> - <java.version>1.8</java.version> + <java.version>17</java.version> </properties> <dependencies> <dependency> @@ -50,7 +50,7 @@ <dependency> <groupId>org.nebula-contrib</groupId> <artifactId>ngbatis</artifactId> - <version>1.2.0-SNAPSHOT</version> + <version>1.2.0-jdk17-beta</version> </dependency> </dependencies> diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Employee.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Employee.java index 94181da3..43fc3ab6 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Employee.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Employee.java @@ -4,9 +4,8 @@ // // This source code is licensed under Apache 2.0 License. -import org.nebula.contrib.ngbatis.annotations.Space; - import jakarta.persistence.Table; +import org.nebula.contrib.ngbatis.annotations.Space; /** * @author yeweicheng diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NoPropertiesVertex.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NoPropertiesVertex.java index 4d661e9b..fc72cc47 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NoPropertiesVertex.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/NoPropertiesVertex.java @@ -4,10 +4,9 @@ // // This source code is licensed under Apache 2.0 License. -import org.nebula.contrib.ngbatis.annotations.Space; - import jakarta.persistence.Id; import jakarta.persistence.Table; +import org.nebula.contrib.ngbatis.annotations.Space; /** * @author yeweicheng diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Person.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Person.java index 30f05b2f..6c703e1a 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Person.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/Person.java @@ -4,12 +4,11 @@ // // This source code is licensed under Apache 2.0 License. -import ye.weicheng.ngbatis.demo.annotations.ValueType; - import jakarta.persistence.Id; import jakarta.persistence.Table; import java.math.BigDecimal; import java.util.Date; +import ye.weicheng.ngbatis.demo.annotations.ValueType; /** * <p>Person的实体类示例</p> diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/TimeTest.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/TimeTest.java index 6b33c2c2..ca6cb745 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/TimeTest.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/pojo/TimeTest.java @@ -7,7 +7,6 @@ import jakarta.persistence.Column; import jakarta.persistence.Id; import jakarta.persistence.Table; - import java.sql.Time; import java.sql.Timestamp; import java.time.Duration; diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java new file mode 100644 index 00000000..adc83292 --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDao.java @@ -0,0 +1,25 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2023 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import java.util.List; + +/** + * 方法中指定该语句不使用space,比如说 create space 等语句-DAO + * @author yeweicheng + * @since 2023-11-10 13:18 + * <br>Now is history! + */ +public interface DropSpaceDao { + + void useTestSpace(); + + void createSpace(); + + void dropSpace(); + + List<String> showTags(); + +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java new file mode 100644 index 00000000..461ebb5a --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlInclude4diffMapperDao.java @@ -0,0 +1,11 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.springframework.data.repository.query.Param; +/** + * nGQL片段跨mapper引用测试 + * 2023-9-7 12:25 lyw. + */ + +public interface NgqlInclude4diffMapperDao { + Integer testInclude(@Param("myInt") Integer myInt); +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java new file mode 100644 index 00000000..5e89251a --- /dev/null +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeDao.java @@ -0,0 +1,15 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.springframework.data.repository.query.Param; +import ye.weicheng.ngbatis.demo.pojo.Person; + +/** + * nGQL片段引用测试 + * 2023-9-7 12:25 lyw. + */ + +public interface NgqlIncludeDao { + Integer testInclude(@Param("myInt") Integer myInt); + + Integer returnAge(@Param("person")Person person); +} diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/TestRepository.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/TestRepository.java index b641f036..28202eec 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/TestRepository.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/TestRepository.java @@ -5,6 +5,10 @@ // This source code is licensed under Apache 2.0 License. import com.vesoft.nebula.client.graph.data.ResultSet; +import jakarta.persistence.Id; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.nebula.contrib.ngbatis.models.data.NgEdge; import org.nebula.contrib.ngbatis.models.data.NgSubgraph; import org.nebula.contrib.ngbatis.models.data.NgVertex; @@ -14,11 +18,6 @@ import ye.weicheng.ngbatis.demo.pojo.Person; import ye.weicheng.ngbatis.demo.pojo.PersonLikePerson; -import jakarta.persistence.Id; -import java.util.List; -import java.util.Map; -import java.util.Set; - /** * 数据访问层 样例。 *<p/> diff --git a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java index 5062e325..5527bbc9 100644 --- a/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java +++ b/ngbatis-demo/src/main/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepository.java @@ -4,11 +4,10 @@ // // This source code is licensed under Apache 2.0 License. +import jakarta.annotation.Resource; import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; import ye.weicheng.ngbatis.demo.pojo.Person; -import jakarta.annotation.Resource; - /** * 数据访问层 样例。 *<p/> @@ -20,4 +19,5 @@ public interface TestRepository extends NebulaDaoBasic<Person, String> { Integer testSameClassName(); + } diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index 9780fd9c..957de5a9 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -4,6 +4,10 @@ server: port: 8083 + +spring: + profiles: + active: ye nebula: ngbatis: diff --git a/ngbatis-demo/src/main/resources/docker-compose.yaml b/ngbatis-demo/src/main/resources/docker-compose.yaml new file mode 100644 index 00000000..687270a8 --- /dev/null +++ b/ngbatis-demo/src/main/resources/docker-compose.yaml @@ -0,0 +1,377 @@ +version: '3.4' +services: + metad0: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.1 + - --ws_ip=172.28.1.1 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.1:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9559:9559" + - 19559 + - 11002 + volumes: + - ./data/meta0:/data/meta:Z + - ./logs/meta0:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + metad1: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.2 + - --ws_ip=172.28.1.2 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.2:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9560:9559" + - 19559 + - 11002 + volumes: + - ./data/meta1:/data/meta:Z + - ./logs/meta1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + metad2: + image: vesoft/nebula-metad:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.1.3 + - --ws_ip=172.28.1.3 + - --port=9559 + - --data_path=/data/meta + - --log_dir=/logs + - --v=0 + - --ws_http_port=19559 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --expired_time_factor=2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.1.3:19559/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9561:9559" + - 19559 + - 11002 + volumes: + - ./data/meta2:/data/meta:Z + - ./logs/meta2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.1.3 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged0: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.1 + - --ws_ip=172.28.2.1 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.1:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9779:9779" + - 19669 + - 12002 + volumes: + - ./data/storage0:/data/storage:Z + - ./logs/storage0:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged1: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.2 + - --ws_ip=172.28.2.2 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.2:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9780:9779" + - 19669 + - 12002 + volumes: + - ./data/storage1:/data/storage:Z + - ./logs/storage1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + storaged2: + image: vesoft/nebula-storaged:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --local_ip=172.28.2.3 + - --ws_ip=172.28.2.3 + - --port=9779 + - --data_path=/data/storage + - --log_dir=/logs + - --v=0 + - --ws_http_port=19779 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.2.3:19779/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9781:9779" + - 19669 + - 12002 + volumes: + - ./data/storage2:/data/storage:Z + - ./logs/storage2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.2.3 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd0: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.1 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.1:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9669:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph0:/logs:Z +# - ./testgraph.ngql:/data/testgraph.ngql +# - type: bind +# source: ./testgraph.ngql +# target: /data/testgraph.ngql + networks: + nebula-net: + ipv4_address: 172.28.3.1 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd1: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.2 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.2:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9670:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph1:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.3.2 + restart: on-failure + cap_add: + - SYS_PTRACE + + graphd2: + image: vesoft/nebula-graphd:nightly + environment: + USER: root + TZ: "${TZ}" + command: + - --meta_server_addrs=172.28.1.1:9559,172.28.1.2:9559,172.28.1.3:9559 + - --port=9669 + - --ws_ip=172.28.3.3 + - --log_dir=/logs + - --v=0 + - --ws_http_port=19669 + - --minloglevel=0 + - --heartbeat_interval_secs=2 + - --timezone_name=+08:00:00 + depends_on: + - metad0 + - metad1 + - metad2 + healthcheck: + test: ["CMD", "curl", "-f", "http://172.28.3.3:19669/status"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + ports: + - "9671:9669" + - 19779 + - 13002 + volumes: + - ./logs/graph2:/logs:Z + networks: + nebula-net: + ipv4_address: 172.28.3.3 + restart: on-failure + cap_add: + - SYS_PTRACE + console: + image: vesoft/nebula-console:nightly + entrypoint: "" + command: + - sh + - -c + - | + sleep 3 && + nebula-console -addr graphd0 -port 9669 -u root -p nebula -f /data/testgraph.ngql && + nebula-console -addr graphd0 -port 9669 -u root -p nebula -e 'ADD HOSTS "172.28.2.1":9779,"172.28.2.2":9779,"172.28.2.3":9779' && + sleep 36000 + volumes: + - ./testgraph.ngql:/data/testgraph.ngql + depends_on: + - graphd0 + networks: + - nebula-net + +networks: + nebula-net: + ipam: + driver: default + config: + - subnet: 172.28.0.0/16 diff --git a/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml new file mode 100644 index 00000000..b1f068fd --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/DropSpaceDao.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (c) 2023 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.DropSpaceDao" space="test_drop"> + + <delete id="dropSpace"> + drop space test_drop; + </delete> + + <select id="useTestSpace" space="test"> + RETURN 1; + </select> + + <select id="createSpace" space="null"> + create space test_drop ( vid_type = INT64 ); + </select> + + <select id="showTags" resultType="java.lang.String"> + SHOW TAGS; + </select> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml b/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml new file mode 100644 index 00000000..d0b9fb14 --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/NgqlInclude4diffMapperDao.xml @@ -0,0 +1,12 @@ +<!-- + Copyright (c) 2022 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.NgqlInclude4diffMapperDao" space="test"> + + <select id="testInclude" resultType="java.lang.Integer"> + RETURN @ng.include('ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao.include-test-value'); + </select> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml new file mode 100644 index 00000000..0213df7b --- /dev/null +++ b/ngbatis-demo/src/main/resources/mapper/NgqlIncludeDao.xml @@ -0,0 +1,28 @@ +<!-- + Copyright (c) 2022 All project authors. All rights reserved. + + This source code is licensed under Apache 2.0 License. +--> +<mapper namespace="ye.weicheng.ngbatis.demo.repository.NgqlIncludeDao" space="test"> + + <select id="testInclude" resultType="java.lang.Integer"> + @ng.include('include-test'); + </select> + + <nGQL id="include-test"> + RETURN @ng.include('include-test-value'); + </nGQL> + + <nGQL id="include-test-value"> + ${myInt} + </nGQL> + + <select id="returnAge" resultType="java.lang.Integer"> + @ng.include('ngql-return-age',person); + </select> + + <nGQL id="ngql-return-age"> + RETURN @ng.include('include-test-value',{'myInt':age}); + </nGQL> + +</mapper> \ No newline at end of file diff --git a/ngbatis-demo/src/main/resources/mapper/TestRepository.xml b/ngbatis-demo/src/main/resources/mapper/TestRepository.xml index 45067bc1..33e40bdd 100644 --- a/ngbatis-demo/src/main/resources/mapper/TestRepository.xml +++ b/ngbatis-demo/src/main/resources/mapper/TestRepository.xml @@ -45,7 +45,7 @@ </select> <select id="selectString"> - match (v:person) return v.person.name as name limit 1 + match (v:person) where v.person.name is not null return v.person.name as name limit 1 </select> <select id="selectStringParam"> @@ -145,7 +145,7 @@ <insert id="insertDynamic" space="test"> @for( v in p0 ) { - @var javaV = @ng_args[0].get(vLP.dataIndex ); + @var javaV = ng.get( ng_args[0], vLP.dataIndex ); @var vid = ng.id( javaV ); @var kv = ng.kv( javaV.propertyList ); @var cols = ng.join( @kv.columns, ",", "ng.schemaFmt" ); diff --git a/ngbatis-demo/src/main/resources/testgraph.ngql b/ngbatis-demo/src/main/resources/testgraph.ngql new file mode 100644 index 00000000..a0d6c7ed --- /dev/null +++ b/ngbatis-demo/src/main/resources/testgraph.ngql @@ -0,0 +1,7 @@ +create space if not exists test (vid_type = fixed_string(32)) +:sleep 20 +use test +create tag if not exists person(name string,gender string,height double,age int32 ,birthday datetime) +create tag if not exists employee(name string,gender string,height double,age int32 ,birthday datetime,position string) +create edge if not exists like(likeness double) +create tag index person_index_1 on person(age,birthday) \ No newline at end of file diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java index 101e904a..fc061eeb 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NebulaBasicDaoTests.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.locationtech.jts.util.Assert; import org.nebula.contrib.ngbatis.models.data.NgPath; +import org.nebula.contrib.ngbatis.models.data.NgTriplet; import org.nebula.contrib.ngbatis.utils.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -60,7 +61,7 @@ public void selectBySelective() { List<Person> people = repository.selectBySelective(person); System.out.println(JSON.toJSONString(people)); } - + @Test public void selectBySelectiveWithBigDecimal() { Person person = new Person(); @@ -68,7 +69,7 @@ public void selectBySelectiveWithBigDecimal() { List<Person> people = repository.selectBySelective(person); System.out.println(JSON.toJSONString(people)); } - + /** * https://github.com/nebula-contrib/ngbatis/issues/35. */ @@ -107,7 +108,7 @@ public void selectIdBySelectiveStringLike() { List<String> people = repository.selectIdBySelectiveStringLike(person); System.out.println(people); } - + @Test public void selectByMap() { Map<String, Object> query = new HashMap<>(); @@ -182,7 +183,7 @@ public void insertSelectiveWithBigDecimal() { @Test public void insertBatch() { long now = System.currentTimeMillis(); - + Person person1 = new Person(); person1.setName("IB" + now); person1.setGender("M"); @@ -192,7 +193,7 @@ public void insertBatch() { person2.setName("IB" + (now + 1)); person2.setAge(18); person2.setBirthday(new Date()); - + Person person3 = new Person(); person3.setName("IB" + (now + 2)); person3.setGender("M"); @@ -200,9 +201,9 @@ public void insertBatch() { List<Person> people = new ArrayList<>(); people.add(person1); - people.add(person2);; + people.add(person2); people.add(person3); - + repository.insertBatch(people); } // endregion @@ -215,14 +216,14 @@ public void updateById() { Person person = new Person(); person.setName(name); repository.insert(person); - + Integer newAge = randomAge(); person.setAge(newAge); person.setGender("F"); repository.updateById(person); - + Person personDb = repository.selectById(name); - + Assert.isTrue(newAge.equals(personDb.getAge())); } @@ -266,7 +267,7 @@ public void updateByIdBatch() { List<Person> people = new ArrayList<>(); people.add(person1); - people.add(person2);; + people.add(person2); people.add(person3); repository.insertBatch(people); @@ -276,17 +277,17 @@ public void updateByIdBatch() { Integer newAge2 = randomAge(); person2.setAge(newAge2); - + Integer newAge3 = randomAge(); person3.setAge(newAge3); - + repository.updateByIdBatchSelective(people); - + List<String> ids = people.stream().map(Person::getName).collect(Collectors.toList()); List<Person> peopleDb = repository.selectByIds(ids); Assert.isTrue(peopleDb.size() == 3); - + for (Person personDb : peopleDb) { for (Person person : people) { if (Objects.equals(personDb.getName(), person.getName())) { @@ -330,6 +331,31 @@ public void deleteById() { int row = repository.deleteById("赵小洋"); System.out.println(row); } + + @Test + public void deleteByIdBatch() { + long now = System.currentTimeMillis(); + Person person1 = new Person(); + person1.setName("UBB" + now); + + Person person2 = new Person(); + person2.setName("UBB" + (now + 1)); + + Person person3 = new Person(); + person3.setName("UBB" + (now + 2)); + + List<Person> people = new ArrayList<>(); + people.add(person1); + people.add(person2); + people.add(person3); + repository.insertBatch(people); + + List<String> peopleIds = new ArrayList<>(); + peopleIds.add(person1.getName()); + peopleIds.add(person2.getName()); + peopleIds.add(person3.getName()); + Assert.equals(repository.deleteByIdBatch(peopleIds),1); + } // endregion // region graph special @@ -384,7 +410,7 @@ public void insertEdgeUseNodeId() { like.setLikeness(0.202210171102); repository.insertEdge("吴小极", like, "刘小洲"); } - + @Test public void insertEdgeUseNodeId2() { LikeWithRank like = new LikeWithRank(); @@ -425,6 +451,26 @@ public void insertEdgeSelective() { repository.insertEdgeSelective(person1, likeWithRank, person2); } + @Test + public void insertEdgeBatch() { + List<NgTriplet<String>> ngTripletList = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + Person person1 = new Person(); + person1.setName("p1_" + i); + repository.insertSelective(person1); + + Person person2 = new Person(); + person2.setName("p2_" + i); + repository.insertSelective(person2); + + Like like = new Like(); + like.setLikeness(0.87); + + ngTripletList.add(new NgTriplet<>(person1,like,person2)); + } + repository.insertEdgeBatch(ngTripletList); + } + @Test public void upsertEdgeSelective() { Person person1 = new Person(); @@ -460,7 +506,7 @@ public void startNode() { Person whoIsStartForTest = repository.startNode(Like.class, "易小海"); System.out.println(JSON.toJSONString(whoIsStartForTest)); } - + @Test public void shortestPath() { List<NgPath<String>> ngPaths = repository.shortestPath("吴小极", "刘小洲"); diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplicationTests.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplicationTests.java index 18181493..e2684e53 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplicationTests.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/NgbatisDemoApplicationTests.java @@ -174,24 +174,17 @@ public void selectByPerson() { @Test public void insertDynamic() { + Map<String, Object> props = new HashMap<>(); + props.put("age", 18); DynamicNode node = new DynamicNode(); node.setTagName("person"); - node.setPropertyList(new HashMap<String, Object>() {{ - put("age", 18); - }} - ); + node.setPropertyList(props); DynamicNode node2 = new DynamicNode(); node2.setTagName("person"); - node2.setPropertyList(new HashMap<String, Object>() {{ - put("age", 18); - }} - ); + node2.setPropertyList(props); DynamicNode node3 = new DynamicNode(); node3.setTagName("person"); - node3.setPropertyList(new HashMap<String, Object>() {{ - put("age", 18); - }} - ); + node3.setPropertyList(props); List<DynamicNode> nodes = Arrays.asList(node, node2, node3); repository.insertDynamic(nodes); } diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java new file mode 100644 index 00000000..d2abbd82 --- /dev/null +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/DropSpaceDaoTest.java @@ -0,0 +1,35 @@ +package ye.weicheng.ngbatis.demo.repository; + +// Copyright (c) 2023 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * @author yeweicheng + * @since 2023-11-10 13:26 + * <br>Now is history! + */ +@SpringBootTest +class DropSpaceDaoTest { + + @Autowired + private DropSpaceDao dao; + + @Test + void dropSpace() throws InterruptedException { + dao.useTestSpace(); + dao.createSpace(); + Thread.sleep(10 * 1000); + + List<String> tags = dao.showTags(); + System.out.println(tags); + + dao.dropSpace(); + } + +} diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/EmployeeDaoTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/EmployeeDaoTest.java index befc2a50..8611c5b8 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/EmployeeDaoTest.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/EmployeeDaoTest.java @@ -5,6 +5,11 @@ // This source code is licensed under Apache 2.0 License. import com.alibaba.fastjson.JSON; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Random; import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -14,11 +19,6 @@ import org.springframework.boot.test.context.SpringBootTest; import ye.weicheng.ngbatis.demo.pojo.Employee; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Random; /** * Multi tags tests. diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java new file mode 100644 index 00000000..dfe8c911 --- /dev/null +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/NgqlIncludeTest.java @@ -0,0 +1,30 @@ +package ye.weicheng.ngbatis.demo.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import ye.weicheng.ngbatis.demo.pojo.Person; + +/** + * TODO + * 2023-9-7 15:23 lyw. + */ +@SpringBootTest +public class NgqlIncludeTest { + + @Autowired + private NgqlIncludeDao ngqlIncludeDao; + @Autowired + private NgqlInclude4diffMapperDao ngqlInclude4diffMapperDao; + + @Test + public void test() { + System.out.println("nGQL引用测试:" + ngqlIncludeDao.testInclude(1)); + Person person = new Person(); + person.setAge(18); + System.out.println("nGQL引用额外参数测试:" + ngqlIncludeDao.returnAge(person)); + System.out.println("nGQL跨mapper引用测试:" + ngqlInclude4diffMapperDao.testInclude(1)); + + } + +} diff --git a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepositoryTest.java b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepositoryTest.java index 4e2ec9b7..8e5dda15 100644 --- a/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepositoryTest.java +++ b/ngbatis-demo/src/test/java/ye/weicheng/ngbatis/demo/repository/resource/TestRepositoryTest.java @@ -4,16 +4,15 @@ // // This source code is licensed under Apache 2.0 License. +import static org.springframework.util.Assert.isTrue; + +import jakarta.annotation.Resource; +import java.util.Objects; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ye.weicheng.ngbatis.demo.repository.TestRepository; -import jakarta.annotation.Resource; -import java.util.Objects; - -import static org.springframework.util.Assert.isTrue; - /** * @author yeweicheng * @since 2023-08-04 17:48 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..34034d93 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,706 @@ +{ + "name": "ngbatis", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ngbatis", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "markdownlint": "^0.31.0", + "markdownlint-cli": "^0.36.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/entities": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.3.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.4.tgz", + "integrity": "sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", + "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/linkify-it": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz", + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/markdown-it": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~3.0.1", + "linkify-it": "^4.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdownlint": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.31.0.tgz", + "integrity": "sha512-e+jZGRGZrz1s0T4wiPDFtyQafq7sKgdbf2sdL46gRT8zLEvDDihQmGeSCV6VXp9BsfkuZ0dPTAg9hf4j6NFgjg==", + "dev": true, + "dependencies": { + "markdown-it": "13.0.1", + "markdownlint-micromark": "0.1.7" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.36.0.tgz", + "integrity": "sha512-h4WdqOam3+QOVOcJSOQuG8KvvN8dlS0OiJhbPwYWBk7VMZR40UtSSMIOpSP5B4EHPHg3W3ILSQUvqg1HNpTCxA==", + "dev": true, + "dependencies": { + "commander": "~11.0.0", + "get-stdin": "~9.0.0", + "glob": "~10.3.4", + "ignore": "~5.2.4", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.2.0", + "markdownlint": "~0.30.0", + "minimatch": "~9.0.3", + "run-con": "~1.3.2" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-cli/node_modules/markdownlint": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.30.0.tgz", + "integrity": "sha512-nInuFvI/rEzanAOArW5490Ez4EYpB5ODqVM0mcDYCPx9DKJWCQqCgejjiCvbSeE7sjbDscVtZmwr665qpF5xGA==", + "dev": true, + "dependencies": { + "markdown-it": "13.0.1", + "markdownlint-micromark": "0.1.7" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz", + "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-con": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~4.1.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..bc2f12ab --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "ngbatis", + "version": "1.0.0", + "description": "<!--\r Copyright (c) 2022 All project authors and nebula-contrib. All rights reserved.", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "scripts": { + "lint-md": "markdownlint *.md docs", + "format-md": "markdownlint --fix *.md docs" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "markdownlint": "^0.31.0", + "markdownlint-cli": "^0.36.0" + } +} diff --git a/pom.xml b/pom.xml index 55d18369..51e2c930 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ <name>ngbatis</name> <groupId>org.nebula-contrib</groupId> <artifactId>ngbatis</artifactId> - <version>1.2.0-SNAPSHOT</version> + <version>1.2.0-jdk17-beta</version> <developers> <developer> @@ -28,11 +28,20 @@ <name>soul-gin</name> <email>1533119789@qq.com</email> </developer> + <developer> + <name>dieyi</name> + <email>admin@zendee.cn</email> + </developer> + <developer> + <name>shbone</name> + <email>598924626@qq.com</email> + </developer> </developers> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> + <beetl.version>3.15.10.RELEASE</beetl.version> </properties> <dependencies> @@ -91,13 +100,28 @@ <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl-spring-jdk17</artifactId> - <version>3.15.8.RELEASE</version> + <version>${beetl.version}</version> + <exclusions> + <exclusion> + <groupId>com.ibeetl</groupId> + <artifactId>beetl-default-antlr4.9-support</artifactId> + </exclusion> + <exclusion> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.ibeetl</groupId> + <artifactId>beetl-antlr4.11-support</artifactId> + <version>${beetl.version}</version> </dependency> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl-springboot-starter-jdk17</artifactId> - <version>3.15.8.RELEASE</version> + <version>${beetl.version}</version> </dependency> <!-- for nGQL escape in xml --> @@ -140,8 +164,8 @@ <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> - <source>1.8</source> - <target>1.8</target> + <source>17</source> + <target>17</target> <generatedSourcesDirectory>src/main/generated</generatedSourcesDirectory> </configuration> </plugin> @@ -281,27 +305,27 @@ </plugin> <!-- GPG plugin --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-gpg-plugin</artifactId> - <version>1.6</version> - <executions> - <execution> - <id>sign-artifacts</id> - <phase>verify</phase> - <goals> - <goal>sign</goal> - </goals> - <configuration> - <!-- Prevent `gpg` from using pinentry programs --> - <gpgArguments> - <arg>--pinentry-mode</arg> - <arg>loopback</arg> - </gpgArguments> - </configuration> - </execution> - </executions> - </plugin> +<!-- <plugin>--> +<!-- <groupId>org.apache.maven.plugins</groupId>--> +<!-- <artifactId>maven-gpg-plugin</artifactId>--> +<!-- <version>1.6</version>--> +<!-- <executions>--> +<!-- <execution>--> +<!-- <id>sign-artifacts</id>--> +<!-- <phase>verify</phase>--> +<!-- <goals>--> +<!-- <goal>sign</goal>--> +<!-- </goals>--> +<!-- <configuration>--> +<!-- <!– Prevent `gpg` from using pinentry programs –>--> +<!-- <gpgArguments>--> +<!-- <arg>--pinentry-mode</arg>--> +<!-- <arg>loopback</arg>--> +<!-- </gpgArguments>--> +<!-- </configuration>--> +<!-- </execution>--> +<!-- </executions>--> +<!-- </plugin>--> <!-- java style check --> <plugin> diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/GetFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/GetFn.java new file mode 100644 index 00000000..531ba8f9 --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/GetFn.java @@ -0,0 +1,21 @@ +package org.nebula.contrib.ngbatis.binding.beetl.functions; + +// Copyright (c) 2022 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +import java.util.List; + +/** + * 通过实体对象,获取 id 值 + * + * @author yeweicheng + * @since 2023-11-21 19:29 + * <br>Now is history! + */ +public class GetFn extends AbstractFunction<List<?>, Integer, Boolean, Void, Void, Void> { + @Override + public Object call(List<?> collection, Integer index) { + return collection.get(index); + } +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java new file mode 100644 index 00000000..b92de28b --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/binding/beetl/functions/IncludeFn.java @@ -0,0 +1,53 @@ +package org.nebula.contrib.ngbatis.binding.beetl.functions; + +import java.util.LinkedHashMap; +import java.util.Map; +import org.beetl.core.Template; +import org.nebula.contrib.ngbatis.models.ClassModel; +import org.nebula.contrib.ngbatis.models.MapperContext; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * TODO + * 2023-9-6 14:28 lyw. + */ +public class IncludeFn extends + AbstractFunction<String, Map<String, Object>, Void, Void, Void, Void> { + + @Override + public Object call(String ngql, Map<String, Object> args) { + if (StringUtils.isEmpty(ngql)) { + throw new RuntimeException("未指定nGQL片段"); + } + int idx = ngql.lastIndexOf("."); + ClassModel classModel; + String ngqlId; + if (idx < 0) { + ngqlId = ngql; + classModel = (ClassModel) ctx.globalVar.get("ng_cm"); + } else { + String namespace = ngql.substring(0, idx); + ngqlId = ngql.substring(idx + 1); + classModel = MapperContext.newInstance().getInterfaces() + .get(namespace + ClassModel.PROXY_SUFFIX); + } + if (CollectionUtils.isEmpty(classModel.getNgqls()) || StringUtils.isEmpty( + classModel.getNgqls().get(ngqlId))) { + throw new RuntimeException("未找到 nGQL(" + ngql + ") 的定义"); + } + Map<String, Object> param; + if (!CollectionUtils.isEmpty(args)) { + //防止同名的 子片段参数 覆盖 父片段参数,导致渲染结果与预期不一致。 + param = new LinkedHashMap<>(ctx.globalVar); + param.putAll(args); + } else { + param = ctx.globalVar; + } + String text = classModel.getNgqls().get(ngqlId).getText(); + Template template = ctx.gt.getTemplate(text); + template.fastBinding(param); + template.renderTo(ctx.byteWriter); + return null; + } +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java index e73a1e4e..f20b108e 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgPathResultHandler.java @@ -7,19 +7,25 @@ import com.vesoft.nebula.client.graph.data.PathWrapper; import com.vesoft.nebula.client.graph.data.ResultSet; import com.vesoft.nebula.client.graph.data.ResultSet.Record; +import jakarta.annotation.Resource; +import java.io.UnsupportedEncodingException; import org.nebula.contrib.ngbatis.models.data.NgPath; import org.nebula.contrib.ngbatis.utils.ResultSetUtil; import org.springframework.stereotype.Component; /** - * Convert the path data from ResultSet to NgPath. + * Convert the path data from ResultSet to NgPath. + * * @author yeweicheng * @since 2023-01-07 4:54 - * <br> Now is history! + * <br> Now is history! */ @Component public class NgPathResultHandler extends AbstractResultHandler<NgPath<?>, NgPath<?>> { + @Resource + private NgVertexResultHandler ngVertexResultHandler; + @Override public NgPath<?> handle(NgPath<?> newResult, ResultSet result, Class resultType) throws NoSuchFieldException, IllegalAccessException, InstantiationException { @@ -29,20 +35,26 @@ public NgPath<?> handle(NgPath<?> newResult, ResultSet result, Class resultType) public NgPath<?> handle(NgPath<?> newResult, Record record) { PathWrapper pathWrapper = ResultSetUtil.getValue(record.values().get(0)); - - pathWrapper.getRelationships().forEach(relationship -> { - NgPath.Relationship ngRelationship = new NgPath.Relationship(); - long ranking = relationship.ranking(); - Object srcId = ResultSetUtil.getValue(relationship.srcId()); - Object dstId = ResultSetUtil.getValue(relationship.dstId()); - String edgeName = relationship.edgeName(); - - ngRelationship.setRank(ranking); - ngRelationship.setSrcID(srcId); - ngRelationship.setDstID(dstId); - ngRelationship.setEdgeName(edgeName); - - newResult.getRelationships().add(ngRelationship); + pathWrapper.getSegments().forEach(segment -> { + try { + NgPath.Relationship ngRelationship = new NgPath.Relationship(); + long ranking = segment.getRelationShip().ranking(); + Object srcId = ResultSetUtil.getValue(segment.getStartNode().getId()); + Object dstId = ResultSetUtil.getValue(segment.getEndNode().getId()); + String edgeName = segment.getRelationShip().edgeName(); + ngRelationship.setRank(ranking); + ngRelationship.setSrcID(srcId); + ngRelationship.setDstID(dstId); + ngRelationship.setEdgeName(edgeName); + ngRelationship.setProperties(ResultSetUtil.edgePropsToMap(segment.getRelationShip())); + + ngVertexResultHandler.handle(ngRelationship.getDst(), segment.getEndNode()); + ngVertexResultHandler.handle(ngRelationship.getSrc(), segment.getStartNode()); + + newResult.getRelationships().add(ngRelationship); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } }); return newResult; } diff --git a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java index 8b741889..0065cb41 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java +++ b/src/main/java/org/nebula/contrib/ngbatis/handler/NgVertexResultHandler.java @@ -18,7 +18,7 @@ import org.springframework.stereotype.Component; /** - * Convert the vertex data from ResultSet to NgVertex. + * Convert the vertex data from ResultSet to NgVertex. * @author yeweicheng * @since 2023-01-07 4:55 * <br> Now is history! @@ -38,10 +38,17 @@ public NgVertex<?> handle(NgVertex<?> newResult, Record row) { handle(newResult, node); return newResult; } - + public NgVertex<?> handle(NgVertex<?> newResult, ValueWrapper nodeValueWrapper) { try { - Node node = nodeValueWrapper.asNode(); + return handle(newResult, nodeValueWrapper.asNode()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + public NgVertex<?> handle(NgVertex<?> newResult, Node node) { + try { ValueWrapper id = node.getId(); newResult.setVid(ResultSetUtil.getValue(id)); List<String> tags = node.tagNames(); @@ -50,7 +57,7 @@ public NgVertex<?> handle(NgVertex<?> newResult, ValueWrapper nodeValueWrapper) return newResult; } catch (UnsupportedEncodingException e) { throw new ResultHandleException( - String.format("%s : %s", e.getClass().toString(), e.getMessage())); + String.format("%s : %s", e.getClass().toString(), e.getMessage())); } } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java index 927c3439..06fa3be2 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java +++ b/src/main/java/org/nebula/contrib/ngbatis/io/MapperResourceLoader.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -36,6 +37,7 @@ import org.nebula.contrib.ngbatis.exception.ResourceLoadException; import org.nebula.contrib.ngbatis.models.ClassModel; import org.nebula.contrib.ngbatis.models.MethodModel; +import org.nebula.contrib.ngbatis.models.NgqlModel; import org.nebula.contrib.ngbatis.utils.Page; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -117,7 +119,7 @@ public Map<String, ClassModel> parseClassModel(Resource resource) // 获取 子节点 List<Node> nodes = element.childNodes(); // 便历子节点,获取 MethodModel - Map<String, MethodModel> methods = parseMethodModel(cm.getNamespace(), nodes); + Map<String, MethodModel> methods = parseMethodModel(cm, nodes); cm.setMethods(methods); result.put(cm.getNamespace().getName() + PROXY_SUFFIX, cm); } @@ -156,21 +158,32 @@ private void setClassModelBySpaceAnnotation(ClassModel cm) { * @param nodes XXXDao.xml 中 <mapper> 下的子标签。即方法标签。 * @return 返回当前XXXDao类的所有方法信息Map,k: 方法名,v:方法模型(即 xml 里一个方法标签的全部信息) */ - private Map<String, MethodModel> parseMethodModel(Class namespace, List<Node> nodes) + private Map<String, MethodModel> parseMethodModel(ClassModel cm, List<Node> nodes) throws NoSuchMethodException { + Class namespace = cm.getNamespace(); Map<String, MethodModel> methods = new HashMap<>(); List<String> methodNames = getMethodNames(nodes); for (Node methodNode : nodes) { if (methodNode instanceof Element) { - MethodModel methodModel = parseMethodModel(methodNode); - addSpaceToSessionPool(methodModel.getSpace()); - Method method = getNameUniqueMethod(namespace, methodModel.getId()); - methodModel.setMethod(method); - Assert.notNull(method, + + + if (((Element) methodNode).tagName().equalsIgnoreCase("nGQL")) { + if (Objects.isNull(cm.getNgqls())) { + cm.setNgqls(new HashMap<>()); + } + NgqlModel ngqlModel = parseNgqlModel((Element) methodNode); + cm.getNgqls().put(ngqlModel.getId(),ngqlModel); + } else { + MethodModel methodModel = parseMethodModel(methodNode); + addSpaceToSessionPool(methodModel.getSpace()); + Method method = getNameUniqueMethod(namespace, methodModel.getId()); + methodModel.setMethod(method); + Assert.notNull(method, "接口 " + namespace.getName() + " 中,未声明 xml 中的出现的方法:" + methodModel.getId()); - checkReturnType(method, namespace); - pageSupport(method, methodModel, methodNames, methods, namespace); - methods.put(methodModel.getId(), methodModel); + checkReturnType(method, namespace); + pageSupport(method, methodModel, methodNames, methods, namespace); + methods.put(methodModel.getId(), methodModel); + } } } return methods; @@ -194,6 +207,16 @@ protected MethodModel parseMethodModel(Node node) { return model; } + + /** + * 解析nGQL语句片段 + * @param ngqlEl xml 中的 <nGQL>标签 + * @return + */ + protected NgqlModel parseNgqlModel(Element ngqlEl) { + return new NgqlModel(ngqlEl.id(),ngqlEl.text()); + } + /** * 对暂未支持的 未封箱基础类型 进行检查并给出友好报错 * @@ -217,21 +240,21 @@ private void checkReturnType(Method method, Class namespace) { * @param methods 用于将需要分页的接口,自动追加两个接口,用于生成动态代理 */ private void pageSupport(Method method, MethodModel methodModel, List<String> methodNames, - Map<String, MethodModel> methods, Class<?> namespace) throws NoSuchMethodException { + Map<String, MethodModel> methods, Class<?> namespace) throws NoSuchMethodException { Class<?>[] parameterTypes = method.getParameterTypes(); List<Class<?>> parameterTypeList = Arrays.asList(parameterTypes); if (parameterTypeList.contains(Page.class)) { int pageParamIndex = parameterTypeList.indexOf(Page.class); MethodModel pageMethod = - createPageMethod( - methodModel, methodNames, parameterTypes, pageParamIndex, namespace - ); + createPageMethod( + methodModel, methodNames, parameterTypes, pageParamIndex, namespace + ); methods.put(pageMethod.getId(), pageMethod); MethodModel countMethod = createCountMethod( methodModel, methodNames, parameterTypes, namespace ); - + methods.put(countMethod.getId(), countMethod); } } @@ -246,11 +269,11 @@ private void pageSupport(Method method, MethodModel methodModel, List<String> me * @return 自动分页的计数方法 */ private MethodModel createCountMethod(MethodModel methodModel, List<String> methodNames, - Class<?>[] parameterTypes, Class<?> namespace) throws NoSuchMethodException { + Class<?>[] parameterTypes, Class<?> namespace) throws NoSuchMethodException { String methodName = methodModel.getId(); String countMethodName = String.format("%s$Count", methodName); Assert.isTrue(!methodNames.contains(countMethodName), - "There is a method name conflicts with " + countMethodName); + "There is a method name conflicts with " + countMethodName); MethodModel countMethodModel = new MethodModel(); setParamAnnotations(parameterTypes, namespace, methodName, countMethodModel); countMethodModel.setParameterTypes(parameterTypes); @@ -277,12 +300,12 @@ private MethodModel createCountMethod(MethodModel methodModel, List<String> meth * @return 查询范围条目方法 的方法模型 */ private MethodModel createPageMethod(MethodModel methodModel, List<String> methodNames, - Class<?>[] parameterTypes, int pageParamIndex, Class<?> namespace) + Class<?>[] parameterTypes, int pageParamIndex, Class<?> namespace) throws NoSuchMethodException { String methodName = methodModel.getId(); String pageMethodName = String.format("%s$Page", methodName); Assert.isTrue(!methodNames.contains(pageMethodName), - "There is a method name conflicts with " + pageMethodName); + "There is a method name conflicts with " + pageMethodName); MethodModel pageMethodModel = new MethodModel(); Annotation[][] parameterAnnotations = setParamAnnotations(parameterTypes, namespace, methodName, pageMethodModel); diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java b/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java index ad063bae..df35e949 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/ClassModel.java @@ -22,6 +22,7 @@ public class ClassModel { private String space; private Map<String, MethodModel> methods; + private Map<String,NgqlModel> ngqls; private ResourceLoader resourceLoader; private Resource resource; @@ -87,4 +88,12 @@ public Class getClazz() { public void setClazz(Class clazz) { this.clazz = clazz; } + + public Map<String, NgqlModel> getNgqls() { + return ngqls; + } + + public void setNgqls(Map<String, NgqlModel> ngqls) { + this.ngqls = ngqls; + } } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java new file mode 100644 index 00000000..1ff455b2 --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/models/NgqlModel.java @@ -0,0 +1,33 @@ +package org.nebula.contrib.ngbatis.models; + +/** + * TODO + * 2023-9-6 15:45 lyw. + */ +public class NgqlModel { + + private String id; + private String text; + + public NgqlModel(String id, String text) { + this.id = id; + this.text = text; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java index e98ca27b..c8483314 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgPath.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic; /** * A common pojo for paths. @@ -15,7 +17,7 @@ * <br> Now is history! */ public class NgPath<I> { - + private List<Relationship<I>> relationships = new ArrayList<>(); public List<Relationship<I>> getRelationships() { @@ -23,16 +25,39 @@ public List<Relationship<I>> getRelationships() { } public void setRelationships( - List<Relationship<I>> relationships) { + List<Relationship<I>> relationships) { this.relationships = relationships; } public static class Relationship<I> { private I dstID; + /** + * Dest vertex entity. If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ + private NgVertex<I> dst = new NgVertex<>(); private String edgeName; private Long rank; private I srcID; + /** + * Source vertex entity. If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ + private NgVertex<I> src = new NgVertex<>(); + + /** + * Attribute of edge. If you want to obtain attributes in an edge, + * you need to use “with prop” in the nGQL. + * <br/> + * {@link NebulaDaoBasic#shortestPath} default without prop + */ + private Map<String,Object> properties; + public I getDstID() { return dstID; } @@ -64,6 +89,30 @@ public I getSrcID() { public void setSrcID(I srcID) { this.srcID = srcID; } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + public NgVertex<I> getDst() { + return dst; + } + + public void setDst(NgVertex<I> dst) { + this.dst = dst; + } + + public NgVertex<I> getSrc() { + return src; + } + + public void setSrc(NgVertex<I> src) { + this.src = src; + } } - + } diff --git a/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java new file mode 100644 index 00000000..c1ea68ab --- /dev/null +++ b/src/main/java/org/nebula/contrib/ngbatis/models/data/NgTriplet.java @@ -0,0 +1,56 @@ +package org.nebula.contrib.ngbatis.models.data; + + +public class NgTriplet<I> { + private I srcId; + private I dstId; + private Object startNode; + private Object edge; + private Object endNode; + + public NgTriplet(Object startNode, Object edge, Object endNode) { + this.startNode = startNode; + this.edge = edge; + this.endNode = endNode; + } + + public I getSrcId() { + return srcId; + } + + public void setSrcId(I srcId) { + this.srcId = srcId; + } + + public I getDstId() { + return dstId; + } + + public void setDstId(I dstId) { + this.dstId = dstId; + } + + public Object getStartNode() { + return startNode; + } + + public void setStartNode(Object startNode) { + this.startNode = startNode; + } + + public Object getEdge() { + return edge; + } + + public void setEdge(Object edge) { + this.edge = edge; + } + + public Object getEndNode() { + return endNode; + } + + public void setEndNode(Object endNode) { + this.endNode = endNode; + } +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java index 182faa51..fcceae1a 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/MapperProxy.java @@ -5,6 +5,7 @@ // This source code is licensed under Apache 2.0 License. import static org.apache.commons.lang3.ObjectUtils.isEmpty; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.nebula.contrib.ngbatis.models.ClassModel.PROXY_SUFFIX; import com.vesoft.nebula.client.graph.SessionPool; @@ -231,7 +232,7 @@ public static ResultSet executeWithParameter(ClassModel cm, MethodModel mm, Stri autoSwitch = qlAndSpace[0] == null ? "" : qlAndSpace[0]; session = localSession.getSession(); result = session.executeWithParameter(gql, params); - localSession.setCurrentSpace(result.getSpaceName()); + localSession.setCurrentSpace(getSpace(result)); if (result.isSucceeded()) { return result; } else { @@ -318,7 +319,7 @@ private static String[] qlWithSpace(LocalSession localSession, String gql, Strin gql = gql.trim(); String sessionSpace = localSession.getCurrentSpace(); boolean sameSpace = Objects.equals(sessionSpace, currentSpace); - if (!sameSpace) { + if (!sameSpace && currentSpace != null) { qlAndSpace[0] = currentSpace; Session session = localSession.getSession(); ResultSet execute = session.execute(String.format("USE `%s`", currentSpace)); @@ -339,11 +340,25 @@ private static String[] qlWithSpace(LocalSession localSession, String gql, Strin * @return 目标space */ public static String getSpace(ClassModel cm, MethodModel mm) { - return mm != null && mm.getSpace() != null ? mm.getSpace() + String methodSpace; + return (mm != null && (methodSpace = mm.getSpace()) != null) + ? ( + "null".equals(methodSpace.trim()) ? null : methodSpace + ) : cm != null && cm.getSpace() != null ? cm.getSpace() : ENV.getSpace(); } + /** + * 从结果集中获取当前的 space + * @param result 脚本执行之后的结果集 + * @return 结果集所对应的 space + */ + private static String getSpace(ResultSet result) { + String spaceName = result.getSpaceName(); + return isBlank(spaceName) ? null : spaceName; + } + public static Logger getLog() { return log; } diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 159b3b14..820307e7 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -292,7 +292,7 @@ default int deleteLogicById(I id) { * @param id 表记录主键 * @return 是否执行成功,成功 1 ,失败 0 */ - default int deleteWithEdgeById(I id) { + default Integer deleteWithEdgeById(I id) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); @@ -307,7 +307,7 @@ default int deleteWithEdgeById(I id) { * @param id 表记录主键 * @return 是否删除成功,成功 1,失败 0 */ - default int deleteById(I id) { + default Integer deleteById(I id) { MethodModel methodModel = getMethodModel(); methodModel.setReturnType(ResultSet.class); methodModel.setResultType(ResultSet.class); @@ -315,7 +315,22 @@ default int deleteById(I id) { ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, id); return resultSet.isSucceeded() ? 1 : 0; } + // endregion + /** + * <p>通过 主键批量删除当前记录</p> + * + * @param ids 表记录主键列表 + * @return 是否删除成功,成功 1,失败 0 + */ + default Integer deleteByIdBatch(Collection<I> ids) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(ResultSet.class); + methodModel.setResultType(ResultSet.class); + ClassModel classModel = getClassModel(this.getClass()); + ResultSet resultSet = (ResultSet) MapperProxy.invoke(classModel, methodModel, ids); + return resultSet.isSucceeded() ? 1 : 0; + } // region graph special /** @@ -334,6 +349,17 @@ default void insertEdge(@NotNull Object v1, @NotNull Object e, @NotNull Object v MapperProxy.invoke(classModel, methodModel, v1, e, v2); } + /** + * @Author sunhb + * @Description 根据三元组列表的头结点,尾节点和尾节点进行插入 + * @Date 2023/10/10 上午11:03 + **/ + default void insertEdgeBatch(List triplets) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, triplets); + } + /** * 根据三元组值, 插入关系 * <p>Selective: 仅处理非空字段</p> @@ -451,7 +477,9 @@ default <E> E startNode(Class<E> startType, Class<?> edgeType, I endId) { * Find the shortest path by srcId and dstId. * @param srcId the start node's id * @param dstId the end node's id - * @return Shortest path list. + * @return Shortest path list. entities containing vertext in path. + * If you want to obtain attributes within an entity, + * you need to use “with prop” in the nGQL. */ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I dstId) { MethodModel methodModel = getMethodModel(); @@ -460,9 +488,8 @@ default List<NgPath<I>> shortestPath(@Param("srcId") I srcId, @Param("dstId") I ClassModel classModel = getClassModel(this.getClass()); return (List<NgPath<I>>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); } - // endregion - -} + // endregion +} diff --git a/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java b/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java index 3f788c36..b8347444 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java +++ b/src/main/java/org/nebula/contrib/ngbatis/utils/ReflectUtil.java @@ -455,7 +455,7 @@ public static Class<?> typeArg(Object o, Class<?> parent, int i) { */ public static Class<?> typeToClass(Type type) throws ClassNotFoundException { if (type instanceof ParameterizedType) { - return ((ParameterizedType) type).getRawType().getClass(); + return (Class<?>)((ParameterizedType) type).getRawType(); } return Class.forName(type.getTypeName()); } diff --git a/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java b/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java index 715211ae..5d91c9ed 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java +++ b/src/main/java/org/nebula/contrib/ngbatis/utils/ResultSetUtil.java @@ -9,6 +9,7 @@ import static org.nebula.contrib.ngbatis.utils.ReflectUtil.isCurrentTypeOrParentType; import static org.nebula.contrib.ngbatis.utils.ReflectUtil.schemaByEntityType; +import com.vesoft.nebula.DateTime; import com.vesoft.nebula.ErrorCode; import com.vesoft.nebula.client.graph.data.DateTimeWrapper; import com.vesoft.nebula.client.graph.data.DateWrapper; @@ -126,27 +127,28 @@ public static <T> T getValue(ValueWrapper valueWrapper, Class<T> resultType) { } private static Object transformDateTime(DateTimeWrapper dateTime) { + DateTime localDateTime = dateTime.getLocalDateTime(); try { CALENDAR_CONSTRUCTOR.setAccessible(true); GregorianCalendar calendar = CALENDAR_CONSTRUCTOR.newInstance( - dateTime.getYear(), - dateTime.getMonth() - 1, - dateTime.getDay(), - dateTime.getHour(), - dateTime.getMinute(), - dateTime.getSecond(), - Math.floorDiv(dateTime.getMicrosec(), 1000) + localDateTime.getYear(), + localDateTime.getMonth() - 1, + localDateTime.getDay(), + localDateTime.getHour(), + localDateTime.getMinute(), + localDateTime.getSec(), + Math.floorDiv(localDateTime.getMicrosec(), 1000) ); CALENDAR_CONSTRUCTOR.setAccessible(false); return calendar.getTime(); } catch (Exception e) { return new GregorianCalendar( - dateTime.getYear(), - dateTime.getMonth() - 1, - dateTime.getDay(), - dateTime.getHour(), - dateTime.getMinute(), - dateTime.getSecond() + localDateTime.getYear(), + localDateTime.getMonth() - 1, + localDateTime.getDay(), + localDateTime.getHour(), + localDateTime.getMinute(), + localDateTime.getSec() ).getTime(); } } diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 40bde3a0..97ed1311 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -3,8 +3,9 @@ This source code is licensed under Apache 2.0 License. --> +<!DOCTYPE mapper SYSTEM "https://nebula-contrib.github.io/ngbatis/ngbatis-mapper.dtd" > <mapper namespace="org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic"> - + <!--region query zoom--> <select id="selectById"> match (n) where id(n) == ${ ng.valueFmt( id ) } return n @@ -283,6 +284,11 @@ <delete id="deleteById"> DELETE VERTEX ${ ng.valueFmt( p0 ) } </delete> + + + <delete id="deleteByIdBatch"> + DELETE VERTEX ${ ng.join( p0, ", ", "ng.valueFmt" ) } + </delete> <!--endregion--> <!--region graph special--> @@ -315,6 +321,22 @@ ); </insert> + <insert id="insertEdgeBatch"> + @for ( row in ng_args[0] ) { + @var kv = ng.kv( row.edge, '', null, null, false ); + @var vId1 = ng.id( row.startNode); + @var rank = ng.id( row.edge, false ); + @var vId2 = ng.id( row.endNode ); + @var e = ng.tagName( row.edge ); + INSERT EDGE `${ e }` ( + ${ ng.join( @kv.columns, ", ", "ng.schemaFmt" ) } + ) + VALUES ${ vId1 }-> ${ vId2 } ${ isNotEmpty( rank ) ? ('@' + rank) : '' } :( + ${ ng.join( @kv.values ) } + ); + @} + </insert> + <insert id="upsertEdgeSelective"> @var kv = ng.kv( ng_args[1], '', null, true, false ); @var rank = ng.id( ng_args[1] ); @@ -359,4 +381,4 @@ </select> <!--endregion--> -</mapper> \ No newline at end of file +</mapper> diff --git a/src/main/resources/beetl.properties b/src/main/resources/beetl.properties index 5942bd02..cd2745d4 100644 --- a/src/main/resources/beetl.properties +++ b/src/main/resources/beetl.properties @@ -15,3 +15,6 @@ FN.ng.id =org.nebula.contrib.ngbatis.binding.beetl.functions.IdFn FN.ng.kv =org.nebula.contrib.ngbatis.binding.beetl.functions.KvFn FN.ng.join = org.nebula.contrib.ngbatis.binding.beetl.functions.JoinFn FN.ng.ifStringLike = org.nebula.contrib.ngbatis.binding.beetl.functions.IfStringLike + +FN.ng.include =org.nebula.contrib.ngbatis.binding.beetl.functions.IncludeFn +FN.ng.get =org.nebula.contrib.ngbatis.binding.beetl.functions.GetFn \ No newline at end of file diff --git a/src/main/resources/ngbatis-mapper.dtd b/src/main/resources/ngbatis-mapper.dtd new file mode 100644 index 00000000..0704415a --- /dev/null +++ b/src/main/resources/ngbatis-mapper.dtd @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<!ELEMENT mapper (insert* | update* | delete* | select* | nGQL*)*> +<!ATTLIST mapper +namespace CDATA #IMPLIED +space CDATA +> + +<!ELEMENT insert (#PCDATA)*> +<!ATTLIST insert +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT update (#PCDATA)*> +<!ATTLIST update +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT delete (#PCDATA)*> +<!ATTLIST delete +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT select (#PCDATA)*> +<!ATTLIST select +id CDATA #REQUIRED +parameterType CDATA #IMPLIED +resultType CDATA #IMPLIED +space CDATA +> + +<!ELEMENT nGQL (#PCDATA)*> +<!ATTLIST nGQL +id CDATA #REQUIRED +> \ No newline at end of file diff --git a/src/test/java/org/nebula/contrib/ngbatis/binding/BeetlTextRenderTest.java b/src/test/java/org/nebula/contrib/ngbatis/binding/BeetlTextRenderTest.java index acb1599c..8d923e16 100644 --- a/src/test/java/org/nebula/contrib/ngbatis/binding/BeetlTextRenderTest.java +++ b/src/test/java/org/nebula/contrib/ngbatis/binding/BeetlTextRenderTest.java @@ -5,6 +5,7 @@ // This source code is licensed under Apache 2.0 License. import com.alibaba.fastjson.JSON; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -74,11 +75,13 @@ public void test2() { + " @}\n" + " RETURN n\n" + " LIMIT 4000"; + List<String> n = new ArrayList<>(); + n.add("name"); String cql = render.resolve( text, new HashMap<String, Object>() {{ - put("columns", Arrays.asList("name")); - put("valueColumns", Arrays.asList("'$name'")); + put("columns", n); + put("valueColumns", n); put("tag", "person"); }} ); From eca999e7e2ee4f4bcb5148aeff390660dc2b5126 Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Tue, 21 Nov 2023 23:24:06 +0800 Subject: [PATCH 55/56] supports jdk17 --- .github/workflows/markdown_lint.yaml | 2 +- .../src/main/resources/application.yml | 4 -- pom.xml | 38 ++++++++++++++----- .../contrib/ngbatis/proxy/NebulaDaoBasic.java | 2 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/.github/workflows/markdown_lint.yaml b/.github/workflows/markdown_lint.yaml index 1b378303..d719b903 100644 --- a/.github/workflows/markdown_lint.yaml +++ b/.github/workflows/markdown_lint.yaml @@ -3,7 +3,7 @@ name: Lint Markdown on: pull_request: - branches: [master] + branches: [ for-jdk17 ] paths: - 'docs/**' - '*.md' diff --git a/ngbatis-demo/src/main/resources/application.yml b/ngbatis-demo/src/main/resources/application.yml index 957de5a9..9780fd9c 100644 --- a/ngbatis-demo/src/main/resources/application.yml +++ b/ngbatis-demo/src/main/resources/application.yml @@ -4,10 +4,6 @@ server: port: 8083 - -spring: - profiles: - active: ye nebula: ngbatis: diff --git a/pom.xml b/pom.xml index 8715a3c6..9acddd8a 100644 --- a/pom.xml +++ b/pom.xml @@ -100,17 +100,15 @@ <groupId>com.ibeetl</groupId> <artifactId>beetl-spring-jdk17</artifactId> <version>${beetl.version}</version> - <artifactId>beetl-spring-jdk17</artifactId> - <version>${beetl.version}</version> <exclusions> - <exclusion> - <groupId>com.ibeetl</groupId> - <artifactId>beetl-default-antlr4.9-support</artifactId> - </exclusion> - <exclusion> - <groupId>org.antlr</groupId> - <artifactId>antlr4-runtime</artifactId> - </exclusion> + <exclusion> + <groupId>com.ibeetl</groupId> + <artifactId>beetl-default-antlr4.9-support</artifactId> + </exclusion> + <exclusion> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + </exclusion> </exclusions> </dependency> <dependency> @@ -306,6 +304,26 @@ </plugin> <!-- GPG plugin --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-gpg-plugin</artifactId> + <version>1.6</version> + <executions> + <execution> + <id>sign-artifacts</id> + <phase>verify</phase> + <goals> + <goal>sign</goal> + </goals> + <configuration> + <!-- Prevent `gpg` from using pinentry programs --> + <gpgArguments> + <arg>--pinentry-mode</arg> + <arg>loopback</arg> + </gpgArguments> + </configuration> + </execution> + </executions> </plugin> <!-- java style check --> diff --git a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index d8704436..730c4201 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -13,13 +13,13 @@ import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.proxy; import static org.nebula.contrib.ngbatis.proxy.NebulaDaoBasicExt.vertexName; -import com.sun.istack.NotNull; import com.vesoft.nebula.client.graph.data.ResultSet; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import org.jetbrains.annotations.NotNull; import org.nebula.contrib.ngbatis.exception.QueryException; import org.nebula.contrib.ngbatis.models.ClassModel; import org.nebula.contrib.ngbatis.models.MethodModel; From 805b475d55089a4364a2d26deaaaf3a59281cfac Mon Sep 17 00:00:00 2001 From: CorvusYe <CorvusY@foxmail.com> Date: Tue, 21 Nov 2023 23:44:02 +0800 Subject: [PATCH 56/56] lint: CHANGELOG.md --- CHANGELOG.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4920ca..d0e2628e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,10 +22,10 @@ This source code is licensed under Apache 2.0 License. - [ ] Geography - [x] Duration +# 1.2.0-jdk-17-beta + ## Dependencies upgrade -- [x] Springboot 3.x support. -# 1.2.0-JDK-17-beta -## Dependencies upgrade + - Upgrade to `JDK 17` and SpringBoot `3.x` - nebula-java: 3.5.0 -> 3.6.0 - beetl: 3.1.8-RELEASE -> 3.15.10.RELEASE @@ -57,7 +57,7 @@ This source code is licensed under Apache 2.0 License. - `@Component("namedMapper")`: use `@Resource("namedMapper$Proxy")` to inject. (since v1.0) - `@Resource("namedComponent")`: use `@Resource("namedComponent")` to inject. (new feature) - fix: when DAO/Mapper method has `Page` type param with `@Param`, the param name can not be use. - > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... + > 如原来项目中分页相关接口,用了不起作用的 `@Param`, 但 xml 还是使用 p0, p1... > 需要将 `@Param` 移除,或者将 xml 中的参数名改成 注解的参数名,以保证参数名统一 - fix:class 'ResultSetUtil.java' parse datetime type error. ([#241](https://github.com/nebula-contrib/ngbatis/pull/241), via [爱吃辣条的Jerry](https://github.com/bobobod)) @@ -109,7 +109,6 @@ This source code is licensed under Apache 2.0 License. <artifactId>spring-boot-starter-aop</artifactId> </dependency> - # 1.1.5 ## 1.1.5 Bugfix @@ -305,7 +304,7 @@ This source code is licensed under Apache 2.0 License. > 对集合进行格式化 参数位 | 参数说明 | 类型 | 必传 | 默认值 - ---|---|---|---|--- + ---|---|---|---|--- 1 | 待格式化的集合 | Iterable | Y 2 | 元素间的分隔符 | String | N | `,` 3 | 函数名,各元素拼接前,可进行函数名指定的格式化函数先行格式化,再拼接 | String | N | null