Step 2.3 - Finalize Repositories with SqlDialectProvider Integration

This commit is contained in:
Jan 2026-01-25 19:30:45 +01:00
parent 1084c5b1cd
commit eff5d26ea3
10 changed files with 142 additions and 71 deletions

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.materials.Material;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
@ -18,10 +19,12 @@ import java.util.stream.Collectors;
public class MaterialRepository {
JdbcTemplate jdbcTemplate;
SqlDialectProvider dialectProvider;
@Autowired
public MaterialRepository(JdbcTemplate jdbcTemplate) {
public MaterialRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
private static String buildCountQuery(String filter, boolean excludeDeprecated) {
@ -39,7 +42,7 @@ public class MaterialRepository {
return queryBuilder.toString();
}
private static String buildQuery(String filter, boolean excludeDeprecated) {
private String buildQuery(String filter, boolean excludeDeprecated, SearchQueryPagination pagination) {
StringBuilder queryBuilder = new StringBuilder("""
SELECT id, name, part_number, normalized_part_number, hs_code, is_deprecated
FROM material WHERE 1=1""");
@ -50,7 +53,8 @@ public class MaterialRepository {
if (filter != null) {
queryBuilder.append(" AND (name LIKE ? OR part_number LIKE ? ) ");
}
queryBuilder.append(" ORDER BY normalized_part_number LIMIT ? OFFSET ?");
queryBuilder.append(" ORDER BY normalized_part_number ");
queryBuilder.append(dialectProvider.buildPaginationClause(pagination.getLimit(), pagination.getOffset()));
return queryBuilder.toString();
}
@ -102,13 +106,15 @@ public class MaterialRepository {
@Transactional
public SearchQueryResult<Material> listMaterials(Optional<String> filter, boolean excludeDeprecated, SearchQueryPagination pagination) {
String query = buildQuery(filter.orElse(null), excludeDeprecated);
String query = buildQuery(filter.orElse(null), excludeDeprecated, pagination);
Object[] paginationParams = dialectProvider.getPaginationParameters(pagination.getLimit(), pagination.getOffset());
var materials = filter.isPresent() ?
jdbcTemplate.query(query, new MaterialMapper(),
filter.get() + "%", filter.get() + "%", pagination.getLimit(), pagination.getOffset()) :
filter.get() + "%", filter.get() + "%", paginationParams[0], paginationParams[1]) :
jdbcTemplate.query(query, new MaterialMapper(),
pagination.getLimit(), pagination.getOffset());
paginationParams[0], paginationParams[1]);
String countQuery = buildCountQuery(filter.orElse(null), excludeDeprecated);

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.service.api.EUTaxationApiService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@ -10,19 +11,26 @@ import java.util.List;
public class NomenclatureRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
private final EUTaxationApiService eUTaxationApiService;
public NomenclatureRepository(JdbcTemplate jdbcTemplate, EUTaxationApiService eUTaxationApiService) {
public NomenclatureRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider, EUTaxationApiService eUTaxationApiService) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
this.eUTaxationApiService = eUTaxationApiService;
}
public List<String> searchHsCode(String search) {
String sql = """
SELECT hs_code FROM nomenclature WHERE hs_code LIKE CONCAT(?, '%') LIMIT 10
""";
String concatExpression = dialectProvider.buildConcat("?", "'%'");
String sql = String.format(
"SELECT hs_code FROM nomenclature WHERE hs_code LIKE %s %s",
concatExpression,
dialectProvider.buildPaginationClause(10, 0)
);
return jdbcTemplate.queryForList (sql, String.class, search);
Object[] paginationParams = dialectProvider.getPaginationParameters(10, 0);
return jdbcTemplate.queryForList(sql, String.class, search, paginationParams[0], paginationParams[1]);
}
}

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.country;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.dto.generic.PropertyDTO;
import de.avatic.lcc.model.db.properties.CountryPropertyMappingId;
import de.avatic.lcc.model.db.rates.ValidityPeriodState;
@ -20,9 +21,11 @@ public class CountryPropertyRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
public CountryPropertyRepository(JdbcTemplate jdbcTemplate) {
public CountryPropertyRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
@Transactional
@ -44,11 +47,14 @@ public class CountryPropertyRepository {
return;
}
String query = """
INSERT INTO country_property (property_value, country_id, country_property_type_id, property_set_id) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE property_value = ?
""";
String query = dialectProvider.buildUpsertStatement(
"country_property",
List.of("property_set_id", "country_property_type_id", "country_id"),
List.of("property_value", "country_id", "country_property_type_id", "property_set_id"),
List.of("property_value")
);
int affectedRows = jdbcTemplate.update(query, value, countryId, typeId, setId, value);
int affectedRows = jdbcTemplate.update(query, value, countryId, typeId, setId);
if(!(affectedRows > 0))
throw new DatabaseException("Could not update property value for country " + countryId + " and property type " + mappingId);
@ -184,9 +190,12 @@ public class CountryPropertyRepository {
LEFT JOIN country_property AS property ON property.country_property_type_id = type.id
LEFT JOIN property_set AS propertySet ON propertySet.id = property.property_set_id WHERE propertySet.state = 'VALID'""";
String insertQuery = dialectProvider.buildInsertIgnoreStatement(
"country_property",
List.of("property_value", "country_id", "country_property_type_id", "property_set_id")
);
jdbcTemplate.query(query, (rs, rowNum) -> {
String insertQuery = "INSERT IGNORE INTO country_property (property_value, country_id, country_property_type_id, property_set_id) VALUES (?, ?, ?, ?)";
jdbcTemplate.update(insertQuery, rs.getString("value"), rs.getInt("country_id"), rs.getInt("typeId"), setId);
return null;
});

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.error;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.dto.error.CalculationJobDumpDTO;
import de.avatic.lcc.dto.error.CalculationJobDestinationDumpDTO;
import de.avatic.lcc.dto.error.CalculationJobRouteSectionDumpDTO;
@ -31,16 +32,17 @@ import java.util.Map;
public class DumpRepository {
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final JdbcTemplate jdbcTemplate;
private final PremiseRepository premiseRepository;
private final PremiseTransformer premiseTransformer;
private final SqlDialectProvider dialectProvider;
public DumpRepository(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbcTemplate, PremiseRepository premiseRepository, PremiseTransformer premiseTransformer) {
public DumpRepository(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbcTemplate, PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, SqlDialectProvider dialectProvider) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.jdbcTemplate = jdbcTemplate;
this.premiseRepository = premiseRepository;
this.premiseTransformer = premiseTransformer;
this.dialectProvider = dialectProvider;
}
@Transactional(readOnly = true)
@ -272,20 +274,17 @@ public class DumpRepository {
public SearchQueryResult<CalculationJobDumpDTO> listDumps(SearchQueryPagination searchQueryPagination) {
String calculationJobQuery = """
String calculationJobQuery = String.format("""
SELECT cj.id, cj.premise_id, cj.calculation_date, cj.validity_period_id,
cj.property_set_id, cj.job_state, cj.error_id, cj.user_id
FROM calculation_job cj
ORDER BY id DESC LIMIT :limit OFFSET :offset
""";
ORDER BY id DESC %s
""", dialectProvider.buildPaginationClause(searchQueryPagination.getLimit(), searchQueryPagination.getOffset()));
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("offset", searchQueryPagination.getOffset());
params.addValue("limit", searchQueryPagination.getLimit());
Object[] paginationParams = dialectProvider.getPaginationParameters(searchQueryPagination.getLimit(), searchQueryPagination.getOffset());
var dumps = namedParameterJdbcTemplate.query(
var dumps = jdbcTemplate.query(
calculationJobQuery,
params,
(rs, _) -> {
CalculationJobDumpDTO dto = new CalculationJobDumpDTO();
dto.setId(rs.getInt("id"));
@ -308,7 +307,8 @@ public class DumpRepository {
}
return dto;
});
},
paginationParams[0], paginationParams[1]);
for(var dump : dumps) {
// Load premise details

View file

@ -1,6 +1,7 @@
package de.avatic.lcc.repositories.error;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.error.SysError;
import de.avatic.lcc.model.db.error.SysErrorTraceItem;
import de.avatic.lcc.model.db.error.SysErrorType;
@ -27,10 +28,12 @@ public class SysErrorRepository {
private final JdbcTemplate jdbcTemplate;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final SqlDialectProvider dialectProvider;
public SysErrorRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
public SysErrorRepository(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.dialectProvider = dialectProvider;
}
@Transactional
@ -114,35 +117,40 @@ public class SysErrorRepository {
@Transactional
public SearchQueryResult<SysError> listErrors(Optional<String> filter, SearchQueryPagination pagination) {
StringBuilder whereClause = new StringBuilder();
MapSqlParameterSource parameters = new MapSqlParameterSource();
List<Object> params = new ArrayList<>();
// Build WHERE clause if filter is provided
if (filter.isPresent() && !filter.get().trim().isEmpty()) {
String filterValue = "%" + filter.get().trim() + "%";
whereClause.append(" WHERE (e.title LIKE :filter OR e.message LIKE :filter OR e.code LIKE :filter)");
parameters.addValue("filter", filterValue);
whereClause.append(" WHERE (e.title LIKE ? OR e.message LIKE ? OR e.code LIKE ?)");
params.add(filterValue);
params.add(filterValue);
params.add(filterValue);
}
// Count total elements
String countSql = "SELECT COUNT(*) FROM sys_error e" + whereClause;
Integer totalElements = namedParameterJdbcTemplate.queryForObject(countSql, parameters, Integer.class);
Integer totalElements = params.isEmpty()
? jdbcTemplate.queryForObject(countSql, Integer.class)
: jdbcTemplate.queryForObject(countSql, Integer.class, params.toArray());
// Build main query with pagination
String sql = """
String sql = String.format("""
SELECT e.id, e.user_id, e.title, e.code, e.message, e.pinia,
e.calculation_job_id, e.bulk_operation_id, e.type, e.created_at, e.request
FROM sys_error e
""" + whereClause + """
%s
ORDER BY e.created_at DESC
LIMIT :limit OFFSET :offset
""";
%s
""", whereClause, dialectProvider.buildPaginationClause(pagination.getLimit(), pagination.getOffset()));
// Add pagination parameters
parameters.addValue("limit", pagination.getLimit());
parameters.addValue("offset", pagination.getOffset());
Object[] paginationParams = dialectProvider.getPaginationParameters(pagination.getLimit(), pagination.getOffset());
params.add(paginationParams[0]);
params.add(paginationParams[1]);
// Execute query
List<SysError> errors = namedParameterJdbcTemplate.query(sql, parameters, new SysErrorMapper());
List<SysError> errors = jdbcTemplate.query(sql, new SysErrorMapper(), params.toArray());
// Load trace items for each error
if (!errors.isEmpty()) {

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.packaging;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.properties.PackagingProperty;
import de.avatic.lcc.model.db.properties.PropertyDataType;
import de.avatic.lcc.model.db.properties.PropertyType;
@ -16,9 +17,11 @@ import java.util.Optional;
public class PackagingPropertiesRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
public PackagingPropertiesRepository(JdbcTemplate jdbcTemplate) {
public PackagingPropertiesRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
public List<PackagingProperty> getByPackagingId(Integer id) {
@ -94,11 +97,14 @@ public class PackagingPropertiesRepository {
public void update(Integer packagingId, Integer typeId, String value) {
String query = """
INSERT INTO packaging_property (property_value, packaging_id, packaging_property_type_id) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE property_value = ?""";
String query = dialectProvider.buildUpsertStatement(
"packaging_property",
List.of("packaging_id", "packaging_property_type_id"),
List.of("property_value", "packaging_id", "packaging_property_type_id"),
List.of("property_value")
);
jdbcTemplate.update(query, value, packagingId, typeId, value);
jdbcTemplate.update(query, value, packagingId, typeId);
}
public Integer getTypeIdByMappingId(String mappingId) {
@ -108,11 +114,14 @@ public class PackagingPropertiesRepository {
public void update(Integer packagingId, String typeId, String value) {
String query = """
INSERT INTO packaging_property (property_value, packaging_id, packaging_property_type_id) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE property_value = ?""";
String query = dialectProvider.buildUpsertStatement(
"packaging_property",
List.of("packaging_id", "packaging_property_type_id"),
List.of("property_value", "packaging_id", "packaging_property_type_id"),
List.of("property_value")
);
jdbcTemplate.update(query, value, packagingId, typeId, value);
jdbcTemplate.update(query, value, packagingId, typeId);
}
}

View file

@ -1,6 +1,7 @@
package de.avatic.lcc.repositories.properties;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.properties.PropertySet;
import de.avatic.lcc.model.db.rates.ValidityPeriodState;
import org.springframework.jdbc.core.JdbcTemplate;
@ -23,9 +24,11 @@ import java.util.Optional;
public class PropertySetRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
public PropertySetRepository(JdbcTemplate jdbcTemplate) {
public PropertySetRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
/**
@ -155,16 +158,21 @@ public class PropertySetRepository {
}
public Optional<PropertySet> getByDate(LocalDate date) {
String query = """
String query = String.format("""
SELECT id, start_date, end_date, state
FROM property_set
WHERE DATE(start_date) <= ?
AND (end_date IS NULL OR DATE(end_date) >= ?)
WHERE %s <= ?
AND (end_date IS NULL OR %s >= ?)
ORDER BY start_date DESC
LIMIT 1
""";
%s
""",
dialectProvider.extractDate("start_date"),
dialectProvider.extractDate("end_date"),
dialectProvider.buildPaginationClause(1, 0)
);
var propertySets = jdbcTemplate.query(query, new PropertySetMapper(), date, date);
Object[] paginationParams = dialectProvider.getPaginationParameters(1, 0);
var propertySets = jdbcTemplate.query(query, new PropertySetMapper(), date, date, paginationParams[0], paginationParams[1]);
return propertySets.isEmpty() ? Optional.empty() : Optional.of(propertySets.getFirst());
}

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.users;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.users.App;
import de.avatic.lcc.model.db.users.Group;
import org.springframework.jdbc.core.JdbcTemplate;
@ -31,16 +32,19 @@ public class AppRepository {
private final JdbcTemplate jdbcTemplate;
private final GroupRepository groupRepository;
private final SqlDialectProvider dialectProvider;
/**
* Creates a new AppRepository.
*
* @param jdbcTemplate Spring JdbcTemplate used for executing SQL queries
* @param groupRepository Repository used to resolve group identifiers
* @param dialectProvider SQL dialect provider for database-specific SQL syntax
*/
public AppRepository(JdbcTemplate jdbcTemplate, GroupRepository groupRepository) {
public AppRepository(JdbcTemplate jdbcTemplate, GroupRepository groupRepository, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.groupRepository = groupRepository;
this.dialectProvider = dialectProvider;
}
/**
@ -128,11 +132,13 @@ public class AppRepository {
jdbcTemplate.update("DELETE FROM sys_app_group_mapping WHERE app_id = ?", appId);
return;
} else {
String insertQuery = dialectProvider.buildInsertIgnoreStatement(
"sys_app_group_mapping",
List.of("app_id", "group_id")
);
for (Integer groupId : groups) {
jdbcTemplate.update(
"INSERT IGNORE INTO sys_app_group_mapping (app_id, group_id) VALUES (?, ?)",
appId, groupId
);
jdbcTemplate.update(insertQuery, appId, groupId);
}
}

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.users;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.users.Group;
import de.avatic.lcc.repositories.pagination.SearchQueryPagination;
import de.avatic.lcc.repositories.pagination.SearchQueryResult;
@ -16,26 +17,31 @@ import java.util.List;
@Repository
public class GroupRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
public GroupRepository(JdbcTemplate jdbcTemplate) {
public GroupRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
@Transactional
public SearchQueryResult<Group> listGroups(SearchQueryPagination pagination) {
String query = "SELECT * FROM sys_group ORDER BY group_name LIMIT ? OFFSET ?";
String query = String.format("SELECT * FROM sys_group ORDER BY group_name %s",
dialectProvider.buildPaginationClause(pagination.getLimit(), pagination.getOffset()));
Object[] paginationParams = dialectProvider.getPaginationParameters(pagination.getLimit(), pagination.getOffset());
var groups = jdbcTemplate.query(query, new GroupMapper(),
pagination.getLimit(), pagination.getOffset());
paginationParams[0], paginationParams[1]);
Integer totalCount = jdbcTemplate.queryForObject(
"SELECT COUNT(*) FROM sys_group ORDER BY group_name",
"SELECT COUNT(*) FROM sys_group",
Integer.class
);
return new SearchQueryResult<>(groups, pagination.getPage(), totalCount, pagination.getLimit());
}
@Transactional
@ -63,8 +69,13 @@ public class GroupRepository {
@Transactional
public void updateGroup(Group group) {
String query = "INSERT INTO sys_group (group_name, group_description) VALUES (?, ?) ON DUPLICATE KEY UPDATE group_description = ?";
jdbcTemplate.update(query, group.getName(), group.getDescription(), group.getDescription());
String query = dialectProvider.buildUpsertStatement(
"sys_group",
List.of("group_name"),
List.of("group_name", "group_description"),
List.of("group_description")
);
jdbcTemplate.update(query, group.getName(), group.getDescription());
}
private static class GroupMapper implements RowMapper<Group> {

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.repositories.users;
import de.avatic.lcc.database.dialect.SqlDialectProvider;
import de.avatic.lcc.model.db.ValidityTuple;
import de.avatic.lcc.model.db.nodes.Node;
import de.avatic.lcc.util.exception.base.ForbiddenException;
@ -22,9 +23,11 @@ public class UserNodeRepository {
private final JdbcTemplate jdbcTemplate;
private final SqlDialectProvider dialectProvider;
public UserNodeRepository(JdbcTemplate jdbcTemplate) {
public UserNodeRepository(JdbcTemplate jdbcTemplate, SqlDialectProvider dialectProvider) {
this.jdbcTemplate = jdbcTemplate;
this.dialectProvider = dialectProvider;
}
@Transactional
@ -46,8 +49,11 @@ public class UserNodeRepository {
queryBuilder.append(" AND is_deprecated = FALSE");
}
queryBuilder.append(" LIMIT ?");
params.add(limit);
queryBuilder.append(" ").append(dialectProvider.buildPaginationClause(limit, 0));
Object[] paginationParams = dialectProvider.getPaginationParameters(limit, 0);
params.add(paginationParams[0]);
params.add(paginationParams[1]);
return jdbcTemplate.query(queryBuilder.toString(), new NodeMapper(), params.toArray());
}