From 34953659059e5a918a21fdd5ab3b09a6856381a3 Mon Sep 17 00:00:00 2001 From: Liu Rui Date: Fri, 27 Dec 2024 10:09:12 +0800 Subject: [PATCH] =?UTF-8?q?feat-IQueryAbility-=E6=94=AF=E6=8C=81=E5=AF=B9P?= =?UTF-8?q?G=E6=95=B0=E6=8D=AE=E7=B1=BB=E5=9E=8B=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=9A=84=E6=95=B0=E7=BB=84=E6=AF=94=E8=BE=83?= =?UTF-8?q?=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 1 + .../ximatai/muyun/test/core/TestQuery.java | 104 ++++++++++++++++-- .../ability/curd/std/ISelectAbility.java | 25 +++++ .../net/ximatai/muyun/model/QueryItem.java | 3 +- .../muyun/database/std/DataAccessStd.java | 2 +- .../muyun/database/std/JdbiProducer.java | 3 +- .../std/argument/PgArrayArgumentFactory.java | 27 +++++ .../muyun/database/IDatabaseOperations.java | 2 +- 8 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 muyun-database-std/src/main/java/net/ximatai/muyun/database/std/argument/PgArrayArgumentFactory.java diff --git a/build.gradle.kts b/build.gradle.kts index 37638885..9d0467a5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -74,6 +74,7 @@ subprojects { maven { url = uri("http://192.168.6.205:8081/repository/maven-snapshots/") +// url = uri("http://127.0.0.1:8081/repository/maven-snapshots/") isAllowInsecureProtocol = true credentials { username = findProperty("office.maven.username").toString() diff --git a/muyun-boot/src/test/java/net/ximatai/muyun/test/core/TestQuery.java b/muyun-boot/src/test/java/net/ximatai/muyun/test/core/TestQuery.java index 25eea0ad..ef9cd0ad 100644 --- a/muyun-boot/src/test/java/net/ximatai/muyun/test/core/TestQuery.java +++ b/muyun-boot/src/test/java/net/ximatai/muyun/test/core/TestQuery.java @@ -45,14 +45,14 @@ void setUp() { tableName = testController.getMainTable(); databaseOperations.execute("TRUNCATE TABLE %s".formatted(tableName)); - testController.create(Map.of("id", "1", "name", "test1", "t_create", "2024-01-01 12:00:00")); - testController.create(Map.of("id", "2", "name", "test2", "t_create", "2024-01-02 12:00:00")); - testController.create(Map.of("id", "3", "name", "test3", "t_create", "2024-01-03 12:00:00")); - testController.create(Map.of("id", "4", "name", "test4", "t_create", "2024-01-04 12:00:00")); - testController.create(Map.of("id", "5", "name", "test5", "t_create", "2024-01-05 12:00:00")); - testController.create(Map.of("id", "6", "name", "test6", "t_create", "2024-01-06 12:00:00")); - testController.create(Map.of("id", "7", "name", "test7", "t_create", "2024-01-07 12:00:00")); - testController.create(Map.of("id", "8", "name", "test8", "t_create", "2024-01-08 12:00:00")); + testController.create(Map.of("id", "1", "name", "test1", "av_name", List.of("a"), "t_create", "2024-01-01 12:00:00")); + testController.create(Map.of("id", "2", "name", "test2", "av_name", List.of("a", "b"), "t_create", "2024-01-02 12:00:00")); + testController.create(Map.of("id", "3", "name", "test3", "av_name", List.of("a", "b", "c"), "t_create", "2024-01-03 12:00:00")); + testController.create(Map.of("id", "4", "name", "test4", "av_name", List.of("a", "b", "c", "d"), "t_create", "2024-01-04 12:00:00")); + testController.create(Map.of("id", "5", "name", "test5", "av_name", List.of("a", "b", "c"), "t_create", "2024-01-05 12:00:00")); + testController.create(Map.of("id", "6", "name", "test6", "av_name", List.of("b", "c"), "t_create", "2024-01-06 12:00:00")); + testController.create(Map.of("id", "7", "name", "test7", "av_name", List.of("a", "c"), "t_create", "2024-01-07 12:00:00")); + testController.create(Map.of("id", "8", "name", "test8", "av_name", List.of("c"), "t_create", "2024-01-08 12:00:00")); } @Test @@ -277,6 +277,86 @@ void testRange5() { assertEquals(1, response.getTotal()); } + @Test + @DisplayName("比较两个数组完全相同") + void testPgArrayEqual() { + Map request = Map.of("av_name1", new String[]{"a", "b"}); + + PageResult response = given() + .contentType("application/json") + .queryParam("noPage", true) + .body(request) + .when() + .post("/api%s/view".formatted(path)) + .then() + .statusCode(200) + .extract() + .as(new TypeRef<>() { + }); + + assertEquals(1, response.getTotal()); + } + + @Test + @DisplayName("比较两个数组有交集") + void testPgArrayOverlap() { + Map request = Map.of("av_name2", new String[]{"a", "b"}); + + PageResult response = given() + .contentType("application/json") + .queryParam("noPage", true) + .body(request) + .when() + .post("/api%s/view".formatted(path)) + .then() + .statusCode(200) + .extract() + .as(new TypeRef<>() { + }); + + assertEquals(7, response.getTotal()); + } + + @Test + @DisplayName("获取在能被传入数组所包含的数据") + void testPgArrayContain() { + Map request = Map.of("av_name3", new String[]{"a", "b"}); + + PageResult response = given() + .contentType("application/json") + .queryParam("noPage", true) + .body(request) + .when() + .post("/api%s/view".formatted(path)) + .then() + .statusCode(200) + .extract() + .as(new TypeRef<>() { + }); + + assertEquals(2, response.getTotal()); + } + + @Test + @DisplayName("获取包含了传入数组的数据") + void testPgArrayBeContain() { + Map request = Map.of("av_name4", new String[]{"a", "b"}); + + PageResult response = given() + .contentType("application/json") + .queryParam("noPage", true) + .body(request) + .when() + .post("/api%s/view".formatted(path)) + .then() + .statusCode(200) + .extract() + .as(new TypeRef<>() { + }); + + assertEquals(4, response.getTotal()); + } + } @Path("/test_query") @@ -297,6 +377,7 @@ public void fitOut(TableWrapper wrapper) { wrapper .setPrimaryKey(Column.ID_POSTGRES) .addColumn(Column.of("name").setType(ColumnType.VARCHAR)) + .addColumn(Column.of("av_name").setType(ColumnType.VARCHAR_ARRAY)) .addColumn(Column.of("t_create").setDefaultValue("now()")); } @@ -309,6 +390,13 @@ public List queryItemList() { QueryItem.of("id").setAlias("in_id").setSymbolType(QueryItem.SymbolType.IN), QueryItem.of("id").setAlias("not_in_id").setSymbolType(QueryItem.SymbolType.NOT_IN), QueryItem.of("name").setSymbolType(QueryItem.SymbolType.LIKE), + QueryItem.of("av_name").setSymbolType(QueryItem.SymbolType.PG_ARRAY_EQUAL).setAlias("av_name1"), + QueryItem.of("av_name").setSymbolType(QueryItem.SymbolType.PG_ARRAY_OVERLAP).setAlias("av_name2"), + QueryItem.of("av_name").setSymbolType(QueryItem.SymbolType.PG_ARRAY_CONTAIN).setAlias("av_name3"), + QueryItem.of("av_name").setSymbolType(QueryItem.SymbolType.PG_ARRAY_BE_CONTAIN).setAlias("av_name4"), + QueryItem.of("name").setSymbolType(QueryItem.SymbolType.LIKE), + QueryItem.of("name").setSymbolType(QueryItem.SymbolType.LIKE), + QueryItem.of("name").setSymbolType(QueryItem.SymbolType.LIKE), QueryItem.of("t_create").setTime(true).setSymbolType(QueryItem.SymbolType.RANGE) ); } diff --git a/muyun-core/src/main/java/net/ximatai/muyun/ability/curd/std/ISelectAbility.java b/muyun-core/src/main/java/net/ximatai/muyun/ability/curd/std/ISelectAbility.java index 13ba9b09..268788b5 100644 --- a/muyun-core/src/main/java/net/ximatai/muyun/ability/curd/std/ISelectAbility.java +++ b/muyun-core/src/main/java/net/ximatai/muyun/ability/curd/std/ISelectAbility.java @@ -252,6 +252,31 @@ default PageResult view(Integer page, condition.append(" %s= ? ".formatted(notMark)); params.add(v); break; + case PG_ARRAY_EQUAL, PG_ARRAY_OVERLAP, PG_ARRAY_CONTAIN, PG_ARRAY_BE_CONTAIN: + if (!(v instanceof List list)) { + throw new QueryException("数据比较时参数也应为数组"); + } + + String s = "="; + if (symbolType.equals(QueryItem.SymbolType.PG_ARRAY_OVERLAP)) { + s = "&&"; + } + if (symbolType.equals(QueryItem.SymbolType.PG_ARRAY_CONTAIN)) { + s = "<@"; + } + if (symbolType.equals(QueryItem.SymbolType.PG_ARRAY_BE_CONTAIN)) { + s = "@>"; + } + + String type = "varchar"; + + if (!list.isEmpty() && list.get(0) instanceof Integer) { + type = "int"; + } + + condition.append(" %s ? ".formatted(s)); + params.add(getDB().createArray(list, type)); + break; case RANGE: if (!(v instanceof List list) || list.size() != 2) { throw new QueryException("区间查询%s的内容必须是长度为2的数组".formatted(k)); diff --git a/muyun-core/src/main/java/net/ximatai/muyun/model/QueryItem.java b/muyun-core/src/main/java/net/ximatai/muyun/model/QueryItem.java index 23d02412..b59ac52a 100644 --- a/muyun-core/src/main/java/net/ximatai/muyun/model/QueryItem.java +++ b/muyun-core/src/main/java/net/ximatai/muyun/model/QueryItem.java @@ -47,7 +47,8 @@ public static QueryItem of(String column) { @Schema(description = "比较类型") public enum SymbolType { - EQUAL, NOT_EQUAL, LIKE, IN, NOT_IN, RANGE + EQUAL, NOT_EQUAL, LIKE, IN, NOT_IN, RANGE, + PG_ARRAY_EQUAL, PG_ARRAY_OVERLAP, PG_ARRAY_CONTAIN, PG_ARRAY_BE_CONTAIN } public QueryItem setColumn(String column) { diff --git a/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/DataAccessStd.java b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/DataAccessStd.java index 5be01ea6..0d915258 100644 --- a/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/DataAccessStd.java +++ b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/DataAccessStd.java @@ -212,7 +212,7 @@ public Object execute(String sql) { return null; } - public Array toArray(List list, String type) { + public Array createArray(List list, String type) { try { return getJdbi().withHandle(handle -> { Connection connection = handle.getConnection(); diff --git a/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/JdbiProducer.java b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/JdbiProducer.java index becb1ca5..3074badc 100644 --- a/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/JdbiProducer.java +++ b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/JdbiProducer.java @@ -6,6 +6,7 @@ import jakarta.inject.Inject; import net.ximatai.muyun.database.std.argument.List2JsonArgumentFactory; import net.ximatai.muyun.database.std.argument.Map2JsonArgumentFactory; +import net.ximatai.muyun.database.std.argument.PgArrayArgumentFactory; import org.jdbi.v3.core.Jdbi; import org.jdbi.v3.core.statement.Slf4JSqlLogger; @@ -20,7 +21,7 @@ public class JdbiProducer { public Jdbi createJdbi() { return Jdbi.create(dataSource) .setSqlLogger(new Slf4JSqlLogger()) -// .registerArgument(new StringArrayArgumentFactory()) + .registerArgument(new PgArrayArgumentFactory()) .registerArgument(new Map2JsonArgumentFactory()) .registerArgument(new List2JsonArgumentFactory()); // .installPlugin(new PostgresPlugin()) diff --git a/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/argument/PgArrayArgumentFactory.java b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/argument/PgArrayArgumentFactory.java new file mode 100644 index 00000000..4ef40bbd --- /dev/null +++ b/muyun-database-std/src/main/java/net/ximatai/muyun/database/std/argument/PgArrayArgumentFactory.java @@ -0,0 +1,27 @@ +package net.ximatai.muyun.database.std.argument; + +import org.jdbi.v3.core.argument.AbstractArgumentFactory; +import org.jdbi.v3.core.argument.Argument; +import org.jdbi.v3.core.config.ConfigRegistry; +import org.postgresql.jdbc.PgArray; + +import java.sql.SQLException; +import java.sql.Types; + +public class PgArrayArgumentFactory extends AbstractArgumentFactory { + + public PgArrayArgumentFactory() { + super(Types.ARRAY); // 指定数据库类型为 ARRAY + } + + @Override + protected Argument build(PgArray value, ConfigRegistry config) { + return (position, statement, ctx) -> { + try { + statement.setArray(position, value); + } catch (SQLException e) { + throw new RuntimeException("Error setting PgArray argument", e); + } + }; + } +} diff --git a/muyun-database/src/main/java/net/ximatai/muyun/database/IDatabaseOperations.java b/muyun-database/src/main/java/net/ximatai/muyun/database/IDatabaseOperations.java index 29ad42a6..0ad78014 100644 --- a/muyun-database/src/main/java/net/ximatai/muyun/database/IDatabaseOperations.java +++ b/muyun-database/src/main/java/net/ximatai/muyun/database/IDatabaseOperations.java @@ -119,5 +119,5 @@ default Object getItem(String schema, String tableName, String id) { Object execute(String sql); - Array toArray(List list, String type); + Array createArray(List list, String type); }