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 fc061ee..a307cd8 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,6 +358,31 @@ 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 people = new ArrayList<>(); + people.add(person1); + people.add(person2); + people.add(person3); + repository.insertBatch(people); + + List 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/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java index 85fe9ca..4308497 100644 --- a/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java +++ b/src/main/java/org/nebula/contrib/ngbatis/proxy/NebulaDaoBasic.java @@ -1,497 +1,494 @@ -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 与基本的节点关系操作
- * 以下在方法注释中所说的“对应类型” 均指的是 泛 型T - * - * @author yeweicheng - * @since 2022-06-12 12:21 - *
Now is history! - */ -public interface NebulaDaoBasic { - - // region query zoom - /** - *

通过主键查询对应表的单条记录

- * - * @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); - } - - /** - *

通过多个 id 值查询符合条件的记录

- * - * @param ids 多个 id - * @return 多个 id 对应的节点 - */ - default List selectByIds(@Param("ids") Collection ids) { - MethodModel methodModel = getMethodModel(); - Class currentType = this.getClass(); - Class entityType = entityType(currentType); - methodModel.setResultType(entityType); - ClassModel classModel = getClassModel(this.getClass()); - return (List) MapperProxy.invoke(classModel, methodModel, ids); - } - - /** - *

以实体类为载体,存放查询条件,不为空的属性为查询条件

- * - * @param record 单个节点做为查询条件 - * @return 符合条件节点的集合 - */ - default List selectBySelective(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - *

以实体类为载体,存放查询条件,不为空的属性为查询条件,String 类型的属性使用模糊查询

- * - * @param record 查询条件 - * @return 符合条件的节点集合 - */ - default List selectBySelectiveStringLike(T record) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - *

按条件查出所有符合条件的记录的 主键

- * - * @param record 查询条件 - * @return 符合查询条件的节点 id - */ - default List selectIdBySelective(T record) { - MethodModel methodModel = getMethodModel(); - Class daoType = this.getClass(); - methodModel.setResultType(pkType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - *

按条件查出所有符合条件的记录的 主键 (String字段模糊查询)

- * - * @param record 查询条件 - * @return 符合查询条件的节点 id - */ - default List selectIdBySelectiveStringLike(T record) { - MethodModel methodModel = getMethodModel(); - Class daoType = this.getClass(); - methodModel.setResultType(pkType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List) MapperProxy.invoke(classModel, methodModel, record); - } - - /** - *

通过 map 存放查询参数,查询多条记录并映射成实体类

- * - * @param param 查询条件 - * @return 符合查询条件的节点集合 - */ - default List selectByMap(Map param) { - MethodModel methodModel = getMethodModel(); - methodModel.setReturnType(List.class); - Class daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - return (List) MapperProxy.invoke(classModel, methodModel, param); - } - - /** - *

统计符合条件的记录数

- * - * @param param 查询条件 - * @return 统及符合查询条件的总节点数 - */ - default Long countByMap(Map param) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - return (Long) MapperProxy.invoke(classModel, methodModel, param); - } - - /** - * 查询对应类型的数据并分页 - * - * @param page 分页的参数,与分页结果的容器 - * @return 分页的结果 - */ - default List selectPage(Page page) { - MethodModel methodModel = getMethodModel(); - Long total = countPage(page); - page.setTotal(total); - if (total == 0) { - return Collections.EMPTY_LIST; - } - methodModel.setReturnType(List.class); - Class daoType = this.getClass(); - methodModel.setResultType(entityType(daoType)); - ClassModel classModel = getClassModel(daoType); - List proxy = (List) MapperProxy.invoke(classModel, methodModel, page); - page.setRows(proxy); - return proxy; - } - - default Long countPage(Page page) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - return (Long) MapperProxy.invoke(classModel, methodModel, page); - } - // endregion - - // region insert zoom - /** - *

插入一条记录,全属性插入

- * - * @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; - } - - /** - *

插入非空字段。

- * - * @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 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; - } - - /** - *

更新

- * - * @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 ts) { - MethodModel methodModel = getMethodModel(); - ClassModel classModel = getClassModel(this.getClass()); - MapperProxy.invoke(classModel, methodModel, ts); - } - - /** - *

新增/更新

- *

Selective: 仅处理非空字段

- * - * @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 - /** - *

数据操作,逻辑删除接口,前提当前类 有字段 is_del

- * - * @param id 表记录主键 - * @return 是否执行成功,成功 1 ,失败 0 - */ - default int deleteLogicById(I id) { - throw new QueryException("No implements"); - } - - /** - *

数据操作,根据节点 id 将节点连同其连接的关系一同物理删除

- * - * @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; - } - - /** - *

通过 主键删除当前记录

- * - * @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 - /** - *

通过 主键批量删除当前记录

- * - * @param ids 表记录主键列表 - * @return 是否删除成功,成功 1,失败 0 - */ - default int deleteByIdBatch(List 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 - /** - * 根据三元组值,插入关系 - * - * @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); - } - - /** - * @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); - } - - /** - * 根据三元组值, 插入关系 - *

Selective: 仅处理非空字段

- * - * @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); - } - - /** - * 根据三元组值, 插入关系 - *

Selective: 仅处理非空字段

- * - * @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与关系类型获取所有开始节点,
开始节点类型为当前接口实现类所管理的实体对应的类型 - * - * @param edgeType 关系类型 - * @param endId 结束节点的 id - * @return 开始节点 - */ - default List listStartNodes(Class edgeType, I endId) { - Class startType = entityType(this.getClass()); - return (List) 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 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与关系类型获取第一个开始节点,
开始节点类型为当前接口实现类所管理的实体对应的类型 (对应类型) - * - * @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 开始节点的类型 - * @return 开始节点 - */ - default E startNode(Class startType, Class edgeType, I endId) { - String cqlTpl = getCqlTpl(); - String startVertexName = vertexName(startType); - String edgeName = edgeName(edgeType); - Class 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> 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>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); - } - - - // endregion - -} - - - +// Copyright (c) 2022 All project authors. All rights reserved. +// +// This source code is licensed under Apache 2.0 License. + +package org.nebula.contrib.ngbatis.proxy; + +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 与基本的节点关系操作
+ * 以下在方法注释中所说的“对应类型” 均指的是 泛 型T + * + * @author yeweicheng + * @since 2022-06-12 12:21 + *
Now is history! + */ +public interface NebulaDaoBasic { + + // region query zoom + /** + *

通过主键查询对应表的单条记录

+ * + * @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); + } + + /** + *

通过多个 id 值查询符合条件的记录

+ * + * @param ids 多个 id + * @return 多个 id 对应的节点 + */ + default List selectByIds(@Param("ids") Collection ids) { + MethodModel methodModel = getMethodModel(); + Class currentType = this.getClass(); + Class entityType = entityType(currentType); + methodModel.setResultType(entityType); + ClassModel classModel = getClassModel(this.getClass()); + return (List) MapperProxy.invoke(classModel, methodModel, ids); + } + + /** + *

以实体类为载体,存放查询条件,不为空的属性为查询条件

+ * + * @param record 单个节点做为查询条件 + * @return 符合条件节点的集合 + */ + default List selectBySelective(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + *

以实体类为载体,存放查询条件,不为空的属性为查询条件,String 类型的属性使用模糊查询

+ * + * @param record 查询条件 + * @return 符合条件的节点集合 + */ + default List selectBySelectiveStringLike(T record) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + *

按条件查出所有符合条件的记录的 主键

+ * + * @param record 查询条件 + * @return 符合查询条件的节点 id + */ + default List selectIdBySelective(T record) { + MethodModel methodModel = getMethodModel(); + Class daoType = this.getClass(); + methodModel.setResultType(pkType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + *

按条件查出所有符合条件的记录的 主键 (String字段模糊查询)

+ * + * @param record 查询条件 + * @return 符合查询条件的节点 id + */ + default List selectIdBySelectiveStringLike(T record) { + MethodModel methodModel = getMethodModel(); + Class daoType = this.getClass(); + methodModel.setResultType(pkType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List) MapperProxy.invoke(classModel, methodModel, record); + } + + /** + *

通过 map 存放查询参数,查询多条记录并映射成实体类

+ * + * @param param 查询条件 + * @return 符合查询条件的节点集合 + */ + default List selectByMap(Map param) { + MethodModel methodModel = getMethodModel(); + methodModel.setReturnType(List.class); + Class daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + return (List) MapperProxy.invoke(classModel, methodModel, param); + } + + /** + *

统计符合条件的记录数

+ * + * @param param 查询条件 + * @return 统及符合查询条件的总节点数 + */ + default Long countByMap(Map param) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + return (Long) MapperProxy.invoke(classModel, methodModel, param); + } + + /** + * 查询对应类型的数据并分页 + * + * @param page 分页的参数,与分页结果的容器 + * @return 分页的结果 + */ + default List selectPage(Page page) { + MethodModel methodModel = getMethodModel(); + Long total = countPage(page); + page.setTotal(total); + if (total == 0) { + return Collections.EMPTY_LIST; + } + methodModel.setReturnType(List.class); + Class daoType = this.getClass(); + methodModel.setResultType(entityType(daoType)); + ClassModel classModel = getClassModel(daoType); + List proxy = (List) MapperProxy.invoke(classModel, methodModel, page); + page.setRows(proxy); + return proxy; + } + + default Long countPage(Page page) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + return (Long) MapperProxy.invoke(classModel, methodModel, page); + } + // endregion + + // region insert zoom + /** + *

插入一条记录,全属性插入

+ * + * @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; + } + + /** + *

插入非空字段。

+ * + * @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 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; + } + + /** + *

更新

+ * + * @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 ts) { + MethodModel methodModel = getMethodModel(); + ClassModel classModel = getClassModel(this.getClass()); + MapperProxy.invoke(classModel, methodModel, ts); + } + + /** + *

新增/更新

+ *

Selective: 仅处理非空字段

+ * + * @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 + /** + *

数据操作,逻辑删除接口,前提当前类 有字段 is_del

+ * + * @param id 表记录主键 + * @return 是否执行成功,成功 1 ,失败 0 + */ + default int deleteLogicById(I id) { + throw new QueryException("No implements"); + } + + /** + *

数据操作,根据节点 id 将节点连同其连接的关系一同物理删除

+ * + * @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; + } + + /** + *

通过 主键删除当前记录

+ * + * @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 + /** + *

通过 主键批量删除当前记录

+ * + * @param ids 表记录主键列表 + * @return 是否删除成功,成功 1,失败 0 + */ + default int deleteByIdBatch (Collection 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 + /** + * 根据三元组值,插入关系 + * + * @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); + } + + /** + * @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); + } + + /** + * 根据三元组值, 插入关系 + *

Selective: 仅处理非空字段

+ * + * @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); + } + + /** + * 根据三元组值, 插入关系 + *

Selective: 仅处理非空字段

+ * + * @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与关系类型获取所有开始节点,
开始节点类型为当前接口实现类所管理的实体对应的类型 + * + * @param edgeType 关系类型 + * @param endId 结束节点的 id + * @return 开始节点 + */ + default List listStartNodes(Class edgeType, I endId) { + Class startType = entityType(this.getClass()); + return (List) 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 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与关系类型获取第一个开始节点,
开始节点类型为当前接口实现类所管理的实体对应的类型 (对应类型) + * + * @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 开始节点的类型 + * @return 开始节点 + */ + default E startNode(Class startType, Class edgeType, I endId) { + String cqlTpl = getCqlTpl(); + String startVertexName = vertexName(startType); + String edgeName = edgeName(edgeType); + Class 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> 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>) MapperProxy.invoke(classModel, methodModel, srcId, dstId); + } + + + // endregion + +} diff --git a/src/main/resources/NebulaDaoBasic.xml b/src/main/resources/NebulaDaoBasic.xml index 540068f..97ed131 100644 --- a/src/main/resources/NebulaDaoBasic.xml +++ b/src/main/resources/NebulaDaoBasic.xml @@ -1,381 +1,384 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @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 ) } - ); - - - - @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 ) } - ); - - - - @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 ? '' : ', ' } - @} - - - - - - @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 ? '' : ','} - @} - ; - @} - - - - @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 ? '' : ','} - @} - ; - @} - - - - @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 ? '' : ','} - @} - ; - @} - @} - - - - @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 ? '' : ','} - @} - ; - @} - - - - - - - - - DELETE VERTEX ${ ng.valueFmt( p0 ) } WITH EDGE - - - - DELETE VERTEX ${ ng.valueFmt( p0 ) } - - - - @for ( v in ng_args[0] ) { - DELETE VERTEX ${ ng.valueFmt( v )}; - @} - - - - @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 ) } - ); - - - - @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 ) } - ); - - - @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 ) } - ); - @} - - - @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 ? '' : ',' } - @} - @} - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @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 ) } + ); + + + + @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 ) } + ); + + + + @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 ? '' : ', ' } + @} + + + + + + @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 ? '' : ','} + @} + ; + @} + + + + @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 ? '' : ','} + @} + ; + @} + + + + @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 ? '' : ','} + @} + ; + @} + @} + + + + @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 ? '' : ','} + @} + ; + @} + + + + + + + + + DELETE VERTEX ${ ng.valueFmt( p0 ) } WITH EDGE + + + + DELETE VERTEX ${ ng.valueFmt( p0 ) } + + + + + DELETE VERTEX ${ ng.join( p0, ", ", "ng.valueFmt" ) } + + + + + + @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 ) } + ); + + + + @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 ) } + ); + + + + @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 ) } + ); + @} + + + + @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 ? '' : ',' } + @} + @} + + + + + + + + + + + +