Fix family-member POST: null JPQL param caused bigint <> varchar SQL error
The relationship-uniqueness query used (:excludeId IS NULL OR fm.id <> :excludeId). On create, excludeId is null and PostgreSQL parses the parameter as varchar before the IS NULL branch can short-circuit, so adding a family member returned 403 with "operator does not exist: bigint <> character varying". Split into two queries so neither has a nullable Long parameter. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
45a041b023
commit
026e5fb875
+16
-5
@@ -28,16 +28,27 @@ public interface ClientFamilyMembersRepository
|
||||
extends JpaRepository<ClientFamilyMembers, Long>, JpaSpecificationExecutor<ClientFamilyMembers> {
|
||||
|
||||
/**
|
||||
* Counts non-deleted family members for a client that hold a given relationship code, optionally
|
||||
* ignoring one specific family member (used at update time so a row doesn't conflict with itself).
|
||||
* Backs the single-use relationship rule for Mother / Father / Spouse.
|
||||
* Counts non-deleted family members for a client that hold a given relationship code.
|
||||
* Backs the single-use relationship rule for Mother / Father / Spouse on create.
|
||||
*/
|
||||
@Query("SELECT COUNT(fm) FROM ClientFamilyMembers fm "
|
||||
+ "WHERE fm.client.id = :clientId "
|
||||
+ "AND fm.relationship.id = :relationshipId "
|
||||
+ "AND fm.isDeleted = false "
|
||||
+ "AND (:excludeFamilyMemberId IS NULL OR fm.id <> :excludeFamilyMemberId)")
|
||||
+ "AND fm.isDeleted = false")
|
||||
long countActiveByClientAndRelationship(@Param("clientId") Long clientId,
|
||||
@Param("relationshipId") Long relationshipId);
|
||||
|
||||
// Update variant: excludes one specific row so it doesn't conflict with itself.
|
||||
// Why: PostgreSQL parses parameter types at parse-time; a nullable Long parameter compared with
|
||||
// <> against a bigint column gets bound as varchar when null, producing
|
||||
// "operator does not exist: bigint <> character varying". Splitting create vs. update keeps
|
||||
// both queries non-nullable.
|
||||
@Query("SELECT COUNT(fm) FROM ClientFamilyMembers fm "
|
||||
+ "WHERE fm.client.id = :clientId "
|
||||
+ "AND fm.relationship.id = :relationshipId "
|
||||
+ "AND fm.isDeleted = false "
|
||||
+ "AND fm.id <> :excludeFamilyMemberId")
|
||||
long countActiveByClientAndRelationshipExcluding(@Param("clientId") Long clientId,
|
||||
@Param("relationshipId") Long relationshipId,
|
||||
@Param("excludeFamilyMemberId") Long excludeFamilyMemberId);
|
||||
|
||||
|
||||
+3
-2
@@ -99,8 +99,9 @@ public class ClientFamilyMembersWritePlatformServiceImpl implements ClientFamily
|
||||
if (!SINGLE_USE_RELATIONSHIPS.contains(label)) {
|
||||
return;
|
||||
}
|
||||
final long existing = clientFamilyRepository.countActiveByClientAndRelationship(
|
||||
clientId, relationship.getId(), excludeMemberId);
|
||||
final long existing = (excludeMemberId == null)
|
||||
? clientFamilyRepository.countActiveByClientAndRelationship(clientId, relationship.getId())
|
||||
: clientFamilyRepository.countActiveByClientAndRelationshipExcluding(clientId, relationship.getId(), excludeMemberId);
|
||||
if (existing > 0) {
|
||||
final String displayName = relationship.getLabel();
|
||||
throw new PlatformApiDataValidationException(java.util.List.of(ApiParameterError.parameterError(
|
||||
|
||||
Reference in New Issue
Block a user