|
@@ -0,0 +1,900 @@
|
|
|
|
|
+package com.giantan.data.kvs.repository.index;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
|
+import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.giantan.ai.util.JsonUtil;
|
|
|
|
|
+import com.giantan.ai.util.id.IdGenerator;
|
|
|
|
|
+import com.giantan.ai.util.id.UlidGenerator;
|
|
|
|
|
+import com.giantan.data.kvs.kvstore.GBaseKeyValue;
|
|
|
|
|
+import com.giantan.data.kvs.kvstore.IGDynamicRepository;
|
|
|
|
|
+import com.giantan.data.kvs.repository.*;
|
|
|
|
|
+import com.giantan.data.util.JdbcUtils;
|
|
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
|
|
+
|
|
|
|
|
+import java.sql.Array;
|
|
|
|
|
+import java.sql.PreparedStatement;
|
|
|
|
|
+import java.sql.ResultSet;
|
|
|
|
|
+import java.sql.SQLException;
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+// 增加索引功能
|
|
|
|
|
+// copy from GDynamicRepository.java
|
|
|
|
|
+public class GIndexedRepository implements IGDynamicRepository {
|
|
|
|
|
+
|
|
|
|
|
+ private static final org.slf4j.Logger log
|
|
|
|
|
+ = org.slf4j.LoggerFactory.getLogger(GDynamicRepository.class);
|
|
|
|
|
+
|
|
|
|
|
+ private final ObjectMapper mapper = new ObjectMapper();
|
|
|
|
|
+
|
|
|
|
|
+ protected JdbcTemplate jdbc;
|
|
|
|
|
+
|
|
|
|
|
+ protected String schema;
|
|
|
|
|
+ protected String tablePrefix;
|
|
|
|
|
+ protected String indexPrefix = "core";
|
|
|
|
|
+
|
|
|
|
|
+ private IdGenerator idGenerator = new UlidGenerator();
|
|
|
|
|
+
|
|
|
|
|
+ private IIndexer indexer;
|
|
|
|
|
+
|
|
|
|
|
+ public GIndexedRepository() {
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public GIndexedRepository(String schema, String table) {
|
|
|
|
|
+ this.schema = schema;
|
|
|
|
|
+ this.tablePrefix = table;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public GIndexedRepository(String schema, String table, JdbcTemplate jdbc) {
|
|
|
|
|
+ this.schema = schema;
|
|
|
|
|
+ this.tablePrefix = table;
|
|
|
|
|
+ this.jdbc = jdbc;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String getSchema() {
|
|
|
|
|
+ return schema;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setSchema(String schema) {
|
|
|
|
|
+ this.schema = schema;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String getTablePrefix() {
|
|
|
|
|
+ return tablePrefix;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setTablePrefix(String tablePrefix) {
|
|
|
|
|
+ this.tablePrefix = tablePrefix;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public String getIndexPrefix() {
|
|
|
|
|
+ return indexPrefix;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setIndexPrefix(String indexPrefix) {
|
|
|
|
|
+ this.indexPrefix = indexPrefix;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public IIndexer getIndexer() {
|
|
|
|
|
+ return indexer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setIndexer(IIndexer indexer) {
|
|
|
|
|
+ this.indexer = indexer;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+// protected String fullTableName(String collId) {
|
|
|
|
|
+// return schema + "." + tablePrefix + "_" + collId;// collId.replace("-", "")
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ protected String tableName(String collId) {
|
|
|
|
|
+ return tablePrefix + "_" + collId;// collId.replace("-", "")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// public String indexName(String collId) {
|
|
|
|
|
+// //return schema + "_" + indexPrefix + "_" + collId;
|
|
|
|
|
+// return indexPrefix + "_" + collId;
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ public void setIdGenerator(IdGenerator idGenerator) {
|
|
|
|
|
+ this.idGenerator = idGenerator;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void setJdbcTemplate(JdbcTemplate jdbc) {
|
|
|
|
|
+ this.jdbc = jdbc;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ private String getGid(GBaseKeyValue kv) {
|
|
|
|
|
+ String gid = kv.getGid();
|
|
|
|
|
+ if (gid == null) {
|
|
|
|
|
+ gid = idGenerator.generateId();
|
|
|
|
|
+ kv.setGid(gid);
|
|
|
|
|
+ }
|
|
|
|
|
+ return gid;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String getName(GBaseKeyValue kv) {
|
|
|
|
|
+ String name = kv.getName();
|
|
|
|
|
+ if (name == null) {
|
|
|
|
|
+ name = "";
|
|
|
|
|
+ }
|
|
|
|
|
+ return name;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String toJson(Map<String, Object> m) {
|
|
|
|
|
+ String s = "{}";
|
|
|
|
|
+ if (m == null || m.size() <= 0) {
|
|
|
|
|
+ return s;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ s = mapper.writeValueAsString(m);
|
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
|
+ //throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ return s;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String[] toArray(List ls) {
|
|
|
|
|
+ if (ls == null) {
|
|
|
|
|
+ return new String[0];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return (String[]) ls.toArray(new String[0]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Integer toMark(Integer mark) {
|
|
|
|
|
+ if (mark == null) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ return mark;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected List<String> toList(Array arr) throws SQLException {
|
|
|
|
|
+ if (arr == null) {
|
|
|
|
|
+ return Arrays.asList(); // 或者返回 null,根据需求
|
|
|
|
|
+ }
|
|
|
|
|
+ Object[] data = (Object[]) arr.getArray();
|
|
|
|
|
+ return Arrays.asList((String[]) data);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Map<String, Object> toMap(String json) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
|
|
|
|
|
+ });
|
|
|
|
|
+ return map;
|
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
|
+ throw new RuntimeException(e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 这个比用 new GRowMapper() 高效
|
|
|
|
|
+ private GEntity toGEntry(ResultSet rs) throws SQLException {
|
|
|
|
|
+ GEntity entity = new GEntity();
|
|
|
|
|
+ entity.setId(rs.getLong(GEntityConfig.ID));
|
|
|
|
|
+ entity.setGid(rs.getString(GEntityConfig.GID));
|
|
|
|
|
+ entity.setName(rs.getString(GEntityConfig.NAME));
|
|
|
|
|
+ Array altlabels = rs.getArray(GEntityConfig.ALTLABELS);
|
|
|
|
|
+ if (altlabels != null) {
|
|
|
|
|
+ entity.setAltlabels(toList(altlabels));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ entity.setMark(rs.getInt(GEntityConfig.MARK));
|
|
|
|
|
+ entity.setDescription(rs.getString(GEntityConfig.DESCRIPTION));
|
|
|
|
|
+ Array tags = rs.getArray(GEntityConfig.TAGS);
|
|
|
|
|
+ if (tags != null) {
|
|
|
|
|
+ entity.setTags(toList(tags));
|
|
|
|
|
+ }
|
|
|
|
|
+ entity.setPath(rs.getString(GEntityConfig.PATH));
|
|
|
|
|
+ String s = rs.getString(GEntityConfig.ATTRIBUTES);
|
|
|
|
|
+ if (s != null) {
|
|
|
|
|
+ entity.setAttributes(toMap(s));
|
|
|
|
|
+ }
|
|
|
|
|
+ return entity;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue save(String collId, GBaseKeyValue kvs) throws Throwable {
|
|
|
|
|
+ String sql;
|
|
|
|
|
+ //String gid = getGid(kvs);
|
|
|
|
|
+ GEntity gent = GConverter.toEntity(kvs, idGenerator);
|
|
|
|
|
+ GEntity ret = null;
|
|
|
|
|
+
|
|
|
|
|
+ if (gent.getId() == null) {
|
|
|
|
|
+ // 插入新记录
|
|
|
|
|
+ sql = String.format("INSERT INTO %s.%s (gid, name, altlabels, mark, description, tags, path, attributes) VALUES (?, ?, ?, ?, ?, ?, ?, ?::jsonb) RETURNING * ;", schema, tableName(collId));
|
|
|
|
|
+ ret = jdbc.queryForObject(sql,
|
|
|
|
|
+ new Object[]{gent.getGid(), gent.getName(), toArray(gent.getAltlabels()), gent.getMark(),
|
|
|
|
|
+ gent.getDescription(), toArray(gent.getTags()), gent.getPath(), toJson(gent.getAttributes())},
|
|
|
|
|
+ // new GRowMapper()
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 更新已有记录
|
|
|
|
|
+ sql = String.format("UPDATE %s.%s SET gid = ?, name = ?, altlabels = ?, mark = ?, description = ?, tags = ?, path = ?, attributes = ?::jsonb WHERE id = ? RETURNING * ;", schema, tableName(collId));
|
|
|
|
|
+ ret = jdbc.queryForObject(sql,
|
|
|
|
|
+ new Object[]{gent.getGid(), gent.getName(), toArray(gent.getAltlabels()), gent.getMark(),
|
|
|
|
|
+ gent.getDescription(), toArray(gent.getTags()), gent.getPath(), toJson(gent.getAttributes()), gent.getId()},
|
|
|
|
|
+ //new GRowMapper()
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+ if (ret == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ int r2 = indexer.onAdd(collId, ret);
|
|
|
|
|
+ GBaseKeyValue ret2 = GConverter.fromEntity(ret);
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<Integer> saveAll(String collId, List<GBaseKeyValue> kvs) throws Throwable {
|
|
|
|
|
+ //String sql = String.format("INSERT INTO %s.%s (gid, name, attributes) VALUES (?, ?, ?::jsonb)", schema, tablePrefix);
|
|
|
|
|
+ String sql = String.format("INSERT INTO %s.%s (gid, name, altlabels, mark, description, tags, path, attributes) VALUES (?, ?, ?, ?, ?, ?, ?, ?::jsonb) ", schema, tableName(collId));
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> entities = GConverter.toEntity(kvs, idGenerator);
|
|
|
|
|
+
|
|
|
|
|
+ int[][] batched = jdbc.batchUpdate(sql,
|
|
|
|
|
+ entities,
|
|
|
|
|
+ 50,
|
|
|
|
|
+ (PreparedStatement ps, GEntity entity) -> {
|
|
|
|
|
+ ps.setString(1, entity.getGid());
|
|
|
|
|
+ ps.setString(2, entity.getName());
|
|
|
|
|
+ //ps.setArray(3, toSqlArray(entity.getAltlabels()));
|
|
|
|
|
+ ps.setInt(4, toMark(entity.getMark()));
|
|
|
|
|
+ ps.setString(5, entity.getDescription());
|
|
|
|
|
+ //ps.setArray(6, toSqlArray(entity.getTags()));
|
|
|
|
|
+ ps.setString(7, entity.getPath());
|
|
|
|
|
+ ps.setString(8, toJson(entity.getAttributes())); // 必须是合法 JSON 字符串
|
|
|
|
|
+
|
|
|
|
|
+ JdbcUtils.setStringArray(ps, 3, entity.getAltlabels());
|
|
|
|
|
+ JdbcUtils.setStringArray(ps, 6, entity.getTags());
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ List<Integer> rets = new ArrayList<>();
|
|
|
|
|
+ for (int i = 0; i < batched.length; i++) {
|
|
|
|
|
+ for (int j = 0; j < batched[i].length; j++) {
|
|
|
|
|
+ rets.add(batched[i][j]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ int r2 = indexer.onAdd(collId, entities);
|
|
|
|
|
+ log.info("Save all kvs successfully : {}", rets.size());
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<GBaseKeyValue> findAll(String collId) throws Throwable {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> query = jdbc.query(sql, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ List<GBaseKeyValue> rets = GConverter.fromEntity(query);
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<GBaseKeyValue> findAllByIds(String collId, List<Integer> ids) throws Throwable {
|
|
|
|
|
+ if (ids == null || ids.isEmpty()) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ String placeholders = ids.stream().map(id -> "?").collect(Collectors.joining(","));
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE id IN (" + placeholders + ")", schema, tableName(collId));
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> query = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ ids.toArray(),
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+ List<GBaseKeyValue> rets = GConverter.fromEntity(query);
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue find(String collId, int id) throws Throwable {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE id = ?", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> ret = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ new Object[]{id},
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs) //new EntryRowMapper()
|
|
|
|
|
+ );
|
|
|
|
|
+ if (ret == null || ret.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GBaseKeyValue ret2 = GConverter.fromEntity(ret.get(0));
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue findByGid(String collId, String gid) throws Throwable {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE gid = ?", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> ret = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ new Object[]{gid},
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs) //new EntryRowMapper()
|
|
|
|
|
+ );
|
|
|
|
|
+ if (ret == null || ret.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GBaseKeyValue ret2 = GConverter.fromEntity(ret.get(0));
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<GBaseKeyValue> findByName(String collId, String name) throws Throwable {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE name = ?", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> query = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ new Object[]{name},
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+// List<Map<String, Object>> maps = jdbc.queryForList(sql, name);
|
|
|
|
|
+
|
|
|
|
|
+ List<GBaseKeyValue> rets = GConverter.fromEntity(query);
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<GBaseKeyValue> findByPath(String collId, String path) {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE path = ?", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> query = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ new Object[]{path},
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ List<GBaseKeyValue> rets = GConverter.fromEntity(query);
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<GBaseKeyValue> findByPathPrefix(String collId, String prefix) {
|
|
|
|
|
+ String sql = String.format("SELECT * FROM %s.%s WHERE path LIKE ?", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> query = jdbc.query(
|
|
|
|
|
+ sql,
|
|
|
|
|
+ new Object[]{prefix},
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ List<GBaseKeyValue> rets = GConverter.fromEntity(query);
|
|
|
|
|
+ return rets;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long count(String collId) {
|
|
|
|
|
+ String sql = String.format("SELECT COUNT(*) FROM %s.%s", schema, tableName(collId));
|
|
|
|
|
+ Long l = jdbc.queryForObject(sql, Long.class);
|
|
|
|
|
+ return l;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long delete(String collId, Integer id) {
|
|
|
|
|
+// String sql = String.format("DELETE FROM %s.%s WHERE id = ?", schema, tableName(collId));
|
|
|
|
|
+// return jdbc.update(sql, id);
|
|
|
|
|
+ String sql = String.format("DELETE FROM %s.%s WHERE id = ? RETURNING *", schema, tableName(collId));
|
|
|
|
|
+ List<GEntity> rs = jdbc.query(sql, new GRowMapper(mapper), id);
|
|
|
|
|
+ if (rs == null || rs.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ int r2 = indexer.onDelete(collId, rs.get(0));
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long delete(String collId, List<Integer> ids) {
|
|
|
|
|
+ if (ids == null || ids.isEmpty()) {
|
|
|
|
|
+ return 0L;
|
|
|
|
|
+ }
|
|
|
|
|
+ String placeholders = ids.stream()
|
|
|
|
|
+ .map(id -> "?")
|
|
|
|
|
+ .collect(Collectors.joining(","));
|
|
|
|
|
+
|
|
|
|
|
+ String sql = String.format("DELETE FROM %s.%s WHERE id IN (" + placeholders + ")", schema, tableName(collId));
|
|
|
|
|
+ ////QQQ
|
|
|
|
|
+ Object[] params = ids.toArray();
|
|
|
|
|
+
|
|
|
|
|
+ //return jdbc.update(sql, params);
|
|
|
|
|
+ List<GEntity> rs = jdbc.query(sql, new GRowMapper(mapper), params);
|
|
|
|
|
+ if (rs == null || rs.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ int r2 = indexer.onDelete(collId, rs);
|
|
|
|
|
+ return rs.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long deleteAll(String collId) {
|
|
|
|
|
+ String sql = String.format("DELETE FROM %s.%s", schema, tableName(collId));
|
|
|
|
|
+ int r = jdbc.update(sql);
|
|
|
|
|
+ int r2 = indexer.onDeleteAll(collId);
|
|
|
|
|
+ return r;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //我给你改造一下 updating 方法,加一个 boolean needOldValue 参数,决定是否在更新前先取原记录。思路如下:
|
|
|
|
|
+ //needOldValue = true → 先查询旧记录,再执行 UPDATE
|
|
|
|
|
+ //needOldValue = false → 原来的 UPDATE ... RETURNING * 逻辑
|
|
|
|
|
+ private GEntity updating(String collId, GBaseKeyValue updateFields) throws Throwable {
|
|
|
|
|
+ Object id = updateFields.remove("id");
|
|
|
|
|
+ Object gid = updateFields.remove("gid");
|
|
|
|
|
+
|
|
|
|
|
+ String sql1 = String.format("UPDATE %s.%s SET ", schema, tableName(collId));
|
|
|
|
|
+ StringBuilder sql = new StringBuilder(sql1);
|
|
|
|
|
+
|
|
|
|
|
+ List<String> keys = new ArrayList<>();
|
|
|
|
|
+ updateFields.forEach((key, value) -> {
|
|
|
|
|
+ if (GEntityConfig.UPDATABLE_FIELDS_SET.contains(key)) {
|
|
|
|
|
+ sql.append(key);
|
|
|
|
|
+ if ("attributes".equals(key)) {
|
|
|
|
|
+ sql.append(" = ?::jsonb");
|
|
|
|
|
+ } else if ("altlabels".equals(key) || "tags".equals(key)) {
|
|
|
|
|
+ sql.append(" = ?");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ sql.append(" = ?");
|
|
|
|
|
+ }
|
|
|
|
|
+ sql.append(", ");
|
|
|
|
|
+ keys.add(key);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ sql.setLength(sql.length() - 2); // 移除最后逗号
|
|
|
|
|
+
|
|
|
|
|
+ if (id != null) {
|
|
|
|
|
+ sql.append(" WHERE id = ? RETURNING * ;");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ sql.append(" WHERE gid = ? RETURNING * ;");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(connection -> {
|
|
|
|
|
+ PreparedStatement ps = connection.prepareStatement(sql.toString());
|
|
|
|
|
+
|
|
|
|
|
+ int index = 1;
|
|
|
|
|
+ for (String key : keys) {
|
|
|
|
|
+ Object value = updateFields.get(key);
|
|
|
|
|
+ if ("attributes".equals(key)) {
|
|
|
|
|
+ ps.setString(index++, toJson((Map<String, Object>) value));
|
|
|
|
|
+ } else if ("altlabels".equals(key) || "tags".equals(key)) {
|
|
|
|
|
+ JdbcUtils.setStringArray(ps, index++, (List<String>) value);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ps.setObject(index++, value);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 最后绑定 id/gid
|
|
|
|
|
+ if (id != null) {
|
|
|
|
|
+ ps.setObject(index, id);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ps.setObject(index, gid);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets != null && !rets.isEmpty()) {
|
|
|
|
|
+ return rets.get(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue update(String collId, GBaseKeyValue kv) throws Throwable {
|
|
|
|
|
+ if (kv.size() == 0) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Integer id = kv.getIntId();
|
|
|
|
|
+ String gid = kv.getGid();
|
|
|
|
|
+ String name = kv.getName();
|
|
|
|
|
+
|
|
|
|
|
+ if (id == null && gid == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("ID or GID cannot be null");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ GEntity ret = updating(collId, kv);
|
|
|
|
|
+ if (ret == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ indexer.onUpdate(collId, ret);
|
|
|
|
|
+ GBaseKeyValue ret2 = GConverter.fromEntity(ret);
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+// int rows = updating(kv);
|
|
|
|
|
+//
|
|
|
|
|
+// if (rows == 0) {
|
|
|
|
|
+// String errorMsg = null;
|
|
|
|
|
+// if (gid != null) {
|
|
|
|
|
+// errorMsg = "Update failed, no record found with gid = " + gid;
|
|
|
|
|
+// } else {
|
|
|
|
|
+// errorMsg = "Update failed, no record found with id = " + id;
|
|
|
|
|
+// }
|
|
|
|
|
+// throw new IllegalStateException(errorMsg);
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// GBaseKeyValue ret = null;
|
|
|
|
|
+// if (gid != null) {
|
|
|
|
|
+// ret = findByGid(gid);
|
|
|
|
|
+// } else {
|
|
|
|
|
+// ret = find(id);
|
|
|
|
|
+// }
|
|
|
|
|
+// return ret;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue removeAttribute(String collId, Integer id, List<String> keys) throws Throwable {
|
|
|
|
|
+ if (id == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("ID cannot be null");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (keys.size() == 0) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ Object[] params = new Object[keys.size() + 1];
|
|
|
|
|
+ for (int i = 0; i < keys.size(); i++) {
|
|
|
|
|
+ params[i] = keys.get(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ params[keys.size()] = id;
|
|
|
|
|
+
|
|
|
|
|
+ //String placeholders = String.join("-", keys.stream().map(id1 -> "?").toArray(String[]::new));
|
|
|
|
|
+ String placeholders = keys.stream().map(k -> "?").collect(Collectors.joining("-"));
|
|
|
|
|
+ //String sql = String.format("UPDATE %s.%s SET attributes = attributes - %s WHERE id = ?;", schema, tableName(collId), placeholders);// RETURNING *
|
|
|
|
|
+ // int updated = jdbc.update(sql, params);
|
|
|
|
|
+ // if (updated == 0) {
|
|
|
|
|
+ // return null;
|
|
|
|
|
+ // }
|
|
|
|
|
+ // GBaseKeyValue ret = find(collId, id);
|
|
|
|
|
+ String sql = String.format(
|
|
|
|
|
+ "UPDATE %s.%s SET attributes = attributes - ARRAY[%s]::text[] WHERE id = ? RETURNING *;",
|
|
|
|
|
+ schema, tableName(collId), placeholders
|
|
|
|
|
+ );
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(connection -> {
|
|
|
|
|
+ PreparedStatement ps = connection.prepareStatement(sql);
|
|
|
|
|
+ for (int i = 0; i < params.length; i++) {
|
|
|
|
|
+ ps.setObject(i + 1, params[i]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+
|
|
|
|
|
+ if (rets != null && !rets.isEmpty()) {
|
|
|
|
|
+ GEntity ret = rets.get(0);
|
|
|
|
|
+ int r2 = indexer.onUpdateField(collId, ret, "attributes");
|
|
|
|
|
+ GBaseKeyValue ret2 = GConverter.fromEntity(ret);
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue updateAttribute(String collId, Integer id, String key, Object value) throws Throwable {
|
|
|
|
|
+ return updateAttribute(collId, id, Map.of(key, value));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public GBaseKeyValue updateAttribute(String collId, Integer id, Map<String, Object> attributes) throws Throwable {
|
|
|
|
|
+ if (id == null) {
|
|
|
|
|
+ throw new IllegalArgumentException("ID cannot be null");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (attributes != null && !attributes.isEmpty()) {
|
|
|
|
|
+ String js = JsonUtil.toJsonString(attributes);
|
|
|
|
|
+
|
|
|
|
|
+ //String sql = String.format("UPDATE %s.%s SET attributes = COALESCE(attributes, '{}'::jsonb) || ?::jsonb WHERE id = ?;", schema, table);// RETURNING *
|
|
|
|
|
+ String sql = String.format("UPDATE %s.%s SET attributes = attributes || ?::jsonb WHERE id = ? RETURNING *;", schema, tableName(collId));
|
|
|
|
|
+// int updated = jdbc.update(sql, js, id);
|
|
|
|
|
+// if (updated == 0) {
|
|
|
|
|
+// return null;
|
|
|
|
|
+// }
|
|
|
|
|
+// GBaseKeyValue ret = find(collId, id);
|
|
|
|
|
+// return ret;
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> rs = jdbc.query(sql, new GRowMapper(mapper), js, id);
|
|
|
|
|
+ if (rs == null || rs.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ GEntity entity = rs.get(0);
|
|
|
|
|
+ indexer.onUpdateField(collId, entity, "attributes");
|
|
|
|
|
+ return GConverter.fromEntity(entity);
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Object findAttribute(String collId, Integer id, String attribute) throws SQLException {
|
|
|
|
|
+ String sql = String.format("SELECT attributes->>? FROM %s.%s WHERE id = ?", schema, tableName(collId));
|
|
|
|
|
+ Object o = jdbc.queryForObject(sql, Object.class, attribute, id);
|
|
|
|
|
+ return o;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public long update(String collId, List<GBaseKeyValue> kvs) throws Throwable {
|
|
|
|
|
+ long updatedCount = 0;
|
|
|
|
|
+ for (GBaseKeyValue kv : kvs) {
|
|
|
|
|
+ Integer id = kv.getIntId();
|
|
|
|
|
+ String gid = kv.getGid();
|
|
|
|
|
+
|
|
|
|
|
+ if (id != null || gid != null) {
|
|
|
|
|
+ GEntity updated = updating(collId, kv);
|
|
|
|
|
+ if (updated != null) {
|
|
|
|
|
+ indexer.onUpdate(collId, updated);
|
|
|
|
|
+ updatedCount += 1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return updatedCount;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// public List<String> getAllNames() {
|
|
|
|
|
+// String sql = "SELECT name FROM demo1"; // 选择要查询的字段
|
|
|
|
|
+// return jdbcTemplate.queryForList(sql, String.class); // 返回字段的所有值,类型为 String
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<Map<String, Object>> getAllEntities(String collId, List<String> fields) {
|
|
|
|
|
+ if (fields == null || fields.size() == 0) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ String placeholders = String.join(", ", fields);
|
|
|
|
|
+
|
|
|
|
|
+ String sql = String.format("SELECT %s FROM %s.%s ", placeholders, schema, tableName(collId));
|
|
|
|
|
+ // 使用 queryForList 获取结果,返回一个 List<Map<String, Object>>
|
|
|
|
|
+ return jdbc.queryForList(sql);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<Map<String, Object>> getAllEntities(String collId, List<String> fields, String whereClause) {
|
|
|
|
|
+ if (fields == null || fields.size() == 0) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+ String placeholders = String.join(", ", fields);
|
|
|
|
|
+
|
|
|
|
|
+ String sql = String.format("SELECT %s FROM %s.%s WHERE %s", placeholders, schema, tableName(collId), whereClause);
|
|
|
|
|
+ // 使用 queryForList 获取结果,返回一个 List<Map<String, Object>>
|
|
|
|
|
+ return jdbc.queryForList(sql);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// @Override
|
|
|
|
|
+// public List<String> appendArrayField(String collId, Integer id, String field, List<String> values) {
|
|
|
|
|
+// if (field == null || values == null || values.size() == 0) {
|
|
|
|
|
+// return Collections.emptyList();
|
|
|
|
|
+// }
|
|
|
|
|
+//
|
|
|
|
|
+// Array array1 = toSqlArray(values);
|
|
|
|
|
+// String sql = String.format("UPDATE %s.%s SET %s = %s || ?::text[] WHERE id = ? RETURNING %s", schema, tableName(collId), field, field, field);
|
|
|
|
|
+// List<String> rets = jdbc.queryForObject(
|
|
|
|
|
+// sql,
|
|
|
|
|
+// new Object[]{
|
|
|
|
|
+// array1,
|
|
|
|
|
+// id
|
|
|
|
|
+// },
|
|
|
|
|
+// (rs, rowNum) -> {
|
|
|
|
|
+// Array array = rs.getArray(field);
|
|
|
|
|
+// return toList(array);
|
|
|
|
|
+// }
|
|
|
|
|
+// );
|
|
|
|
|
+// return rets;
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<String> appendArrayField(String collId, Integer id, String field, List<String> values) {
|
|
|
|
|
+ if (field == null || values == null || values.isEmpty()) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String sql = String.format(
|
|
|
|
|
+ "UPDATE %s.%s SET %s = %s || ?::text[] WHERE id = ? RETURNING *",
|
|
|
|
|
+ schema,
|
|
|
|
|
+ tableName(collId),
|
|
|
|
|
+ field,
|
|
|
|
|
+ field,
|
|
|
|
|
+ field
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(
|
|
|
|
|
+ con -> {
|
|
|
|
|
+ PreparedStatement ps = con.prepareStatement(sql);
|
|
|
|
|
+ // 创建 SQL Array 并绑定到参数
|
|
|
|
|
+ //Array sqlArray = con.createArrayOf("text", values.toArray(new String[0]));
|
|
|
|
|
+ //ps.setArray(1, sqlArray);
|
|
|
|
|
+ JdbcUtils.setStringArray(ps, 1, values);
|
|
|
|
|
+ ps.setInt(2, id);
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ GEntity entity = rets.get(0);
|
|
|
|
|
+ indexer.onUpdateField(collId, entity, field);
|
|
|
|
|
+ return getArrayField(entity, field);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private List<String> getArrayField(GEntity entity, String field) {
|
|
|
|
|
+ List<String> ret2 = null;
|
|
|
|
|
+ if (field.equalsIgnoreCase(GEntityConfig.ALTLABELS)) {
|
|
|
|
|
+ ret2 = entity.getAltlabels();
|
|
|
|
|
+ } else if (field.equalsIgnoreCase(GEntityConfig.TAGS)) {
|
|
|
|
|
+ ret2 = entity.getTags();
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret2;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<String> setArrayField(String collId, Integer id, String field, List<String> values) {
|
|
|
|
|
+ if (field == null || values == null) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String sql = String.format(
|
|
|
|
|
+ "UPDATE %s.%s SET %s = ? WHERE id = ? RETURNING %s",
|
|
|
|
|
+ schema, tableName(collId), field, field
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(con -> {
|
|
|
|
|
+ PreparedStatement ps = con.prepareStatement(sql);
|
|
|
|
|
+ // 第 1 个参数:安全设置 array
|
|
|
|
|
+ JdbcUtils.setStringArray(ps, 1, values);
|
|
|
|
|
+ // 第 2 个参数:id
|
|
|
|
|
+ ps.setInt(2, id);
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ GEntity entity = rets.get(0);
|
|
|
|
|
+ indexer.onUpdateField(collId, entity, field);
|
|
|
|
|
+ return getArrayField(entity, field);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<String> removeArrayField(String collId, Integer id, String field, List<String> values) {
|
|
|
|
|
+ if (field == null || values == null || values.size() == 0) {
|
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 构建动态 SQL:array_remove(array_remove(...), ...)
|
|
|
|
|
+ String sql1 = String.format("UPDATE %s.%s SET %s = ", schema, tableName(collId), field);
|
|
|
|
|
+ StringBuilder bs = new StringBuilder(sql1);
|
|
|
|
|
+
|
|
|
|
|
+ StringBuilder bs1 = new StringBuilder();
|
|
|
|
|
+ bs1.append("array_remove(").append(field).append(",").append("?)");
|
|
|
|
|
+ for (int i = 1; i < values.size(); i++) {
|
|
|
|
|
+ bs1.insert(0, "array_remove(");
|
|
|
|
|
+ bs1.append(", ?)");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bs.append(bs1).append(" WHERE id = ? RETURNING ").append(field);
|
|
|
|
|
+
|
|
|
|
|
+ // 参数列表
|
|
|
|
|
+ Object[] args = new Object[values.size() + 1];
|
|
|
|
|
+ for (int i = 0; i < values.size(); i++) {
|
|
|
|
|
+ args[i] = values.get(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ args[values.size()] = id;
|
|
|
|
|
+
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(
|
|
|
|
|
+ bs.toString(),
|
|
|
|
|
+ args,
|
|
|
|
|
+ (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ GEntity entity = rets.get(0);
|
|
|
|
|
+ indexer.onUpdateField(collId, entity, field);
|
|
|
|
|
+ return getArrayField(entity, field);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public int updatePathPrefix(String collId, String oldPrefix, String newPrefix) {
|
|
|
|
|
+ String table = tableName(collId);
|
|
|
|
|
+ String sql = String.format("""
|
|
|
|
|
+ UPDATE %s.%s
|
|
|
|
|
+ SET path = regexp_replace(path, ?, ?)
|
|
|
|
|
+ WHERE path LIKE ?
|
|
|
|
|
+ RETURNING * ;
|
|
|
|
|
+ """, schema, table);
|
|
|
|
|
+
|
|
|
|
|
+ // 正则必须是 ^/a/b/
|
|
|
|
|
+ String regex = "^" + oldPrefix;
|
|
|
|
|
+ String like = oldPrefix + "%";
|
|
|
|
|
+
|
|
|
|
|
+ //return jdbc.update(sql, regex, newPrefix, like);
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(connection -> {
|
|
|
|
|
+ PreparedStatement ps = connection.prepareStatement(sql);
|
|
|
|
|
+ ps.setString(1, regex);
|
|
|
|
|
+ ps.setString(2, newPrefix);
|
|
|
|
|
+ ps.setString(3, like);
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ indexer.onUpdateField(collId, rets, "path");
|
|
|
|
|
+ return rets.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public int updatePathAndNamePrefix(String collId, String oldPrefix, String newPrefix) {
|
|
|
|
|
+ String table = tableName(collId);
|
|
|
|
|
+ // WHERE path LIKE ? OR name LIKE ?;
|
|
|
|
|
+// String sql = String.format("""
|
|
|
|
|
+// UPDATE %s
|
|
|
|
|
+// SET
|
|
|
|
|
+// path = regexp_replace(path, ?::text, ?::text),
|
|
|
|
|
+// name = regexp_replace(name, ?::text, ?::text)
|
|
|
|
|
+// WHERE path LIKE ?;
|
|
|
|
|
+// """, table);
|
|
|
|
|
+//
|
|
|
|
|
+// String regex = "^" + oldPrefix; // 例如 ^/a/b/
|
|
|
|
|
+// String like = oldPrefix + "%"; // 例如 /a/b/%
|
|
|
|
|
+//
|
|
|
|
|
+// return jdbc.update(sql, regex, newPrefix, regex, newPrefix, like);
|
|
|
|
|
+ String regex = "^" + oldPrefix; // 例如 ^/a/b/
|
|
|
|
|
+ String like = oldPrefix + "%"; // 例如 /a/b/%
|
|
|
|
|
+ String sql = String.format("""
|
|
|
|
|
+ UPDATE %s.%s
|
|
|
|
|
+ SET
|
|
|
|
|
+ path = regexp_replace(path, '%s', '%s'),
|
|
|
|
|
+ name = regexp_replace(name, '%s', '%s')
|
|
|
|
|
+ WHERE path LIKE ? RETURNING *
|
|
|
|
|
+ """, schema, table, regex, newPrefix, regex, newPrefix);
|
|
|
|
|
+
|
|
|
|
|
+ //return jdbc.update(sql, like);
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(connection -> {
|
|
|
|
|
+ PreparedStatement ps = connection.prepareStatement(sql);
|
|
|
|
|
+ ps.setString(1, like);
|
|
|
|
|
+ return ps;
|
|
|
|
|
+ }, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ indexer.onUpdateField(collId, rets, "name");
|
|
|
|
|
+ indexer.onUpdateField(collId, rets, "path");
|
|
|
|
|
+ return rets.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int createTable(String collId) {
|
|
|
|
|
+ List<String> sqls = GEntityConfig.createGEntityTable(schema, tableName(collId));
|
|
|
|
|
+ String sql2 = String.join("\n", sqls);
|
|
|
|
|
+ jdbc.execute(sql2);
|
|
|
|
|
+
|
|
|
|
|
+ int r = indexer.createCollection(collId);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int deleteTable(String collId) {
|
|
|
|
|
+ List<String> sqls = GEntityConfig.deleteGEntityTable(schema, tableName(collId));
|
|
|
|
|
+ String sql2 = String.join("\n", sqls);
|
|
|
|
|
+ jdbc.execute(sql2);
|
|
|
|
|
+ int r = indexer.deleteCollection(collId);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int deleteByPath(String collId, String path) {
|
|
|
|
|
+ String sql = String.format("DELETE FROM %s.%s WHERE path = ? RETURNING *", schema, tableName(collId));
|
|
|
|
|
+ //return jdbc.update(sql, path);
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(sql, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ int r = indexer.onDelete(collId, rets);
|
|
|
|
|
+ return rets.size();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int deleteByPathPrefix(String collId, String prefix) {
|
|
|
|
|
+ String like = prefix + "%";
|
|
|
|
|
+ String sql = String.format("DELETE FROM %s.%s WHERE path LIKE ? RETURNING *", schema, tableName(collId));
|
|
|
|
|
+ //return jdbc.update(sql, like);
|
|
|
|
|
+ List<GEntity> rets = jdbc.query(sql, (rs, rowNum) -> toGEntry(rs));
|
|
|
|
|
+ if (rets == null || rets.isEmpty()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ int r = indexer.onDelete(collId, rets);
|
|
|
|
|
+ return rets.size();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|