package jnpf.dmsMapper; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.io.Resources; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ResultMapping; import org.apache.ibatis.session.Configuration; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class DmsWenjianBianhaoMapperXmlTest { private static final List MAPPERS = Arrays.asList( "DmsWenjianBianhaoGuizeMapper", "DmsWenjianBianhaoGuizeZixiangMapper", "DmsWenjianBianhaoLiushuiJishuMapper", "DmsWenjianBianhaoMapper", "DmsWenjianBianhaoShenqingMapper", "DmsWenjianMingchengBiangengShenqingMapper"); @Test void serialCounterBindsStartOnlyForInitializationAndKeepsAtomicIncrement() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoLiushuiJishuMapper")); MappedStatement statement = configuration.getMappedStatement( DmsWenjianBianhaoLiushuiJishuMapper.class.getName() + ".next"); assertTrue(statement.isFlushCacheRequired(), "同一批次相同分组不能复用本地查询缓存"); assertFalse(statement.isUseCache()); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("guizeLiushuihao", "family-1"); parameters.put("liushuiKey", "QC-{SERIAL:4}"); parameters.put("startValue", 100L); org.apache.ibatis.mapping.BoundSql bound = statement.getBoundSql(parameters); org.junit.jupiter.api.Assertions.assertEquals( Arrays.asList("tenantId", "guizeLiushuihao", "liushuiKey", "startValue"), bound.getParameterMappings().stream().map(p -> p.getProperty()).toList()); String sql = normalize(bound.getSql()); assertTrue(sql.contains("VALUES (?, ?, ?, ?) ON CONFLICT (f_tenant_id, guize_liushuihao, liushui_key_hash)")); assertTrue(sql.contains("DO UPDATE SET dangqian_zhi = dms_wenjian_bianhao_gongxiang_jishu.dangqian_zhi + 1 WHERE dms_wenjian_bianhao_gongxiang_jishu.liushui_key = EXCLUDED.liushui_key RETURNING dangqian_zhi")); } @Test void allFileNumberMappersUseXmlWithoutSelectStar() throws IOException { for (String mapper : MAPPERS) { String resource = resource(mapper); String xml; try (Reader reader = Resources.getResourceAsReader(resource)) { xml = read(reader); } assertFalse(xml.toUpperCase().contains("SELECT *"), resource); parse(resource); } } @Test void ruleQueriesLoadQianpiyeSnapshotSourceWithExplicitMappings() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoGuizeMapper")); for (String query : Arrays.asList("selectEnabled", "selectActiveById")) { String statementId = DmsWenjianBianhaoGuizeMapper.class.getName() + "." + query; assertMapping(configuration, statementId, "qianpiye_id", "qianpiyeId"); assertMapping(configuration, statementId, "qianpiye_files", "qianpiyeFiles"); String select = normalize(configuration.getMappedStatement(statementId) .getBoundSql(new HashMap<>()).getSql()).split(" FROM ")[0]; assertTrue(select.contains("changqu")); assertTrue(configuration.getMappedStatement(statementId).getResultMaps().get(0) .getResultMappings().stream().anyMatch(mapping -> "changqu".equals(mapping.getColumn()) && "changqu".equals(mapping.getProperty()))); assertTrue(select.contains("qianpiye_id")); assertTrue(select.contains("qianpiye_files")); } } @Test void ruleVersionCheckExcludesTheCurrentRuleOnlyWhenAnIdIsProvided() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoGuizeMapper")); MappedStatement statement = configuration.getMappedStatement( DmsWenjianBianhaoGuizeMapper.class.getName() + ".countByLiushuihaoAndBanbenhao"); Map parameters = new HashMap<>(); parameters.put("guizeLiushuihao", "serial-1"); parameters.put("banbenhao", "V2"); parameters.put("id", "rule-current"); assertTrue(normalize(statement.getBoundSql(parameters).getSql()).contains("f_id <> ?")); parameters.put("id", ""); assertFalse(normalize(statement.getBoundSql(parameters).getSql()).contains("f_id <> ?")); } @Test void ruleQueriesLoadApprovalStateAndOnlyOfferEnabledApprovedRules() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoGuizeMapper")); for (String query : Arrays.asList("selectEnabled", "selectActiveById")) { String statementId = DmsWenjianBianhaoGuizeMapper.class.getName() + "." + query; assertMapping(configuration, statementId, "banbenhao", "banbenhao"); assertMapping(configuration, statementId, "f_flow_state", "flowState"); String sql = normalize(configuration.getMappedStatement(statementId) .getBoundSql(new HashMap<>()).getSql()); assertTrue(sql.split(" FROM ")[0].contains("banbenhao")); assertTrue(sql.split(" FROM ")[0].contains("f_flow_state")); if ("selectEnabled".equals(query)) { assertTrue(sql.contains("AND biz_enabled = 'enabled'")); assertTrue(sql.contains("AND f_flow_state = 2")); assertFalse(sql.contains("biz_enabled IS NULL")); assertFalse(sql.contains("biz_enabled <>")); } } } @Test void ruleAndPartQueriesMapCompleteSourceRows() throws IOException { for (String mapper : Arrays.asList("DmsWenjianBianhaoGuizeMapper", "DmsWenjianBianhaoGuizeZixiangMapper")) { Configuration configuration = parse(resource(mapper)); boolean main = mapper.equals("DmsWenjianBianhaoGuizeMapper"); for (String query : main ? Arrays.asList("selectEnabled", "selectActiveById") : Arrays.asList("selectActiveByRule")) { String statementId = "jnpf.dmsMapper." + mapper + "." + query; assertMapping(configuration, statementId, "snapshot_data", "snapshotData"); String sql = normalize(configuration.getMappedStatement(statementId) .getBoundSql(new HashMap<>()).getSql()); assertTrue(sql.contains("to_jsonb(" + (main ? "r" : "p") + ")::text AS snapshot_data")); } } } @Test void customNumberContentIsLoadedWithApplicationRows() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoMapper")); for (String query : List.of("selectByApplication", "selectByApplicationForUpdate")) { String id = DmsWenjianBianhaoMapper.class.getName() + "." + query; assertMapping(configuration, id, "zidingyi_neirong", "zidingyiNeirong"); assertTrue(normalize(configuration.getMappedStatement(id).getBoundSql(new HashMap<>()).getSql()) .split(" FROM ")[0].contains("zidingyi_neirong")); } } @Test void applicationFlowStateHasExplicitResultMapping() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoShenqingMapper")); assertMapping(configuration, DmsWenjianBianhaoShenqingMapper.class.getName() + ".selectByFlowForUpdate", "f_flow_state", "flowState"); } @Test void nameChangeFlowStateHasExplicitResultMapping() throws IOException { Configuration configuration = parse( resource("DmsWenjianMingchengBiangengShenqingMapper")); assertMapping(configuration, DmsWenjianMingchengBiangengShenqingMapper.class.getName() + ".selectByFlowForUpdate", "f_flow_state", "flowState"); } @Test void usingNumberCandidatesExcludeActiveNameChangesButEchoRemainsAvailable() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoMapper")); String statementId = DmsWenjianBianhaoMapper.class.getName() + ".selectUsingPage"; Map parameters = new HashMap<>(); parameters.put("bianhaoId", ""); parameters.put("keyword", ""); String candidateSql = normalize(configuration.getMappedStatement(statementId) .getBoundSql(parameters).getSql()); assertTrue(candidateSql.contains("NOT EXISTS")); assertTrue(candidateSql.contains("c.f_flow_state IN (1, 5, 6, 8, 10)")); parameters.put("bianhaoId", "number-1"); String echoSql = normalize(configuration.getMappedStatement(statementId) .getBoundSql(parameters).getSql()); assertFalse(echoSql.contains("NOT EXISTS")); assertTrue(echoSql.contains("b.f_id = ?")); } @Test void newNumberCandidatesExcludeHistoricalResourcesWithoutBreakingEcho() throws IOException { Configuration configuration = parse(resource("DmsWenjianBianhaoMapper")); MappedStatement statement = configuration.getMappedStatement( DmsWenjianBianhaoMapper.class.getName() + ".selectAvailableNewPage"); Map parameters = new HashMap<>(); parameters.put("bianhaoId", ""); parameters.put("keyword", ""); String candidateSql = normalize(statement.getBoundSql(parameters).getSql()); assertTrue(candidateSql.contains("FROM dms_wenjian_ziyuan r")); assertTrue(candidateSql.contains("r.wenjian_bianhao_id = b.f_id OR r.wenjian_bianhao = b.wenjian_bianhao")); assertFalse(candidateSql.contains("r.f_delete_mark")); parameters.put("bianhaoId", "number-1"); String echoSql = normalize(statement.getBoundSql(parameters).getSql()); assertFalse(echoSql.contains("FROM dms_wenjian_ziyuan r")); assertTrue(echoSql.contains("b.f_id = ?")); } private Configuration parse(String resource) throws IOException { Configuration configuration = new Configuration(); try (InputStream common = Resources.getResourceAsStream("mapper/BusinessFileOccupancyMapper.xml")) { new XMLMapperBuilder(common,configuration,"mapper/BusinessFileOccupancyMapper.xml",configuration.getSqlFragments()).parse(); } try (InputStream input = Resources.getResourceAsStream(resource)) { XMLMapperBuilder builder = new XMLMapperBuilder( input, configuration, resource, configuration.getSqlFragments()); builder.parse(); } return configuration; } private void assertMapping(Configuration configuration, String statementId, String column, String property) { MappedStatement statement = configuration.getMappedStatement(statementId); boolean mapped = statement.getResultMaps().stream() .flatMap(resultMap -> resultMap.getResultMappings().stream()) .anyMatch(mapping -> matches(mapping, column, property)); assertTrue(mapped, column + " must map explicitly to " + property); } private boolean matches(ResultMapping mapping, String column, String property) { return column.equals(mapping.getColumn()) && property.equals(mapping.getProperty()); } private String read(Reader reader) throws IOException { StringBuilder result = new StringBuilder(); char[] buffer = new char[2048]; int length; while ((length = reader.read(buffer)) >= 0) { result.append(buffer, 0, length); } return result.toString(); } private String normalize(String sql) { return sql.replaceAll("\\s+", " ").trim(); } private String resource(String mapper) { return "mapper/" + mapper + ".xml"; } }