RelationHypothesisRepository.java
package com.taxonomy.relations.repository;
import com.taxonomy.model.HypothesisStatus;
import com.taxonomy.model.RelationType;
import com.taxonomy.relations.model.RelationHypothesis;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface RelationHypothesisRepository extends JpaRepository<RelationHypothesis, Long> {
String PRIMARY_SCOPE = " h.repositoryId IN ("
+ "SELECT repository.repositoryId FROM SystemRepository repository "
+ "WHERE repository.primaryRepo = true)";
// ── Explicit repository/workspace tenant scope ─────────────────
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.workspaceId IS NULL
ORDER BY h.id
""")
List<RelationHypothesis> findCentralByRepository(
@Param("repositoryId") String repositoryId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.workspaceId IS NULL
AND h.status = :status
ORDER BY h.id
""")
List<RelationHypothesis> findCentralByRepositoryAndStatus(
@Param("repositoryId") String repositoryId,
@Param("status") HypothesisStatus status);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND (h.workspaceId = :workspaceId OR h.workspaceId IS NULL)
ORDER BY h.id
""")
List<RelationHypothesis> findVisibleByRepositoryAndWorkspace(
@Param("repositoryId") String repositoryId,
@Param("workspaceId") String workspaceId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND (h.workspaceId = :workspaceId OR h.workspaceId IS NULL)
AND h.status = :status
ORDER BY h.id
""")
List<RelationHypothesis> findVisibleByRepositoryAndWorkspaceAndStatus(
@Param("repositoryId") String repositoryId,
@Param("workspaceId") String workspaceId,
@Param("status") HypothesisStatus status);
/** Looks up a hypothesis in exactly one mutable repository/workspace scope. */
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.id = :id
AND ((:workspaceId IS NULL AND h.workspaceId IS NULL)
OR h.workspaceId = :workspaceId)
""")
Optional<RelationHypothesis> findByIdInRepositoryWorkspace(
@Param("repositoryId") String repositoryId,
@Param("id") Long id,
@Param("workspaceId") String workspaceId);
/** Looks up a readable hypothesis, including the selected repository's central baseline. */
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.id = :id
AND ((:workspaceId IS NULL AND h.workspaceId IS NULL)
OR (:workspaceId IS NOT NULL
AND (h.workspaceId = :workspaceId OR h.workspaceId IS NULL)))
""")
Optional<RelationHypothesis> findByIdVisibleInRepositoryWorkspace(
@Param("repositoryId") String repositoryId,
@Param("id") Long id,
@Param("workspaceId") String workspaceId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.analysisSessionId = :analysisSessionId
AND ((:workspaceId IS NULL AND h.workspaceId IS NULL)
OR h.workspaceId = :workspaceId)
ORDER BY h.id
""")
List<RelationHypothesis> findByAnalysisSessionIdInRepositoryWorkspace(
@Param("repositoryId") String repositoryId,
@Param("workspaceId") String workspaceId,
@Param("analysisSessionId") String analysisSessionId);
@Query("""
SELECT CASE WHEN COUNT(h) > 0 THEN true ELSE false END
FROM RelationHypothesis h
WHERE h.repositoryId = :repositoryId
AND h.sourceNodeId = :sourceNodeId
AND h.targetNodeId = :targetNodeId
AND h.relationType = :relationType
AND h.analysisSessionScopeKey = :analysisSessionScopeKey
AND h.workspaceScopeKey = :workspaceScopeKey
""")
boolean existsInRepositoryWorkspaceSession(
@Param("repositoryId") String repositoryId,
@Param("workspaceScopeKey") String workspaceScopeKey,
@Param("analysisSessionScopeKey") String analysisSessionScopeKey,
@Param("sourceNodeId") String sourceNodeId,
@Param("targetNodeId") String targetNodeId,
@Param("relationType") RelationType relationType);
List<RelationHypothesis> findByRepositoryIdAndWorkspaceId(
String repositoryId, String workspaceId);
// ── Primary-repository compatibility boundary ──────────────────
// Historic signatures remain available while callers migrate. They are
// deliberately primary-repository scoped and never query every tenant.
@Override
@Query("SELECT h FROM RelationHypothesis h WHERE " + PRIMARY_SCOPE + " ORDER BY h.id")
List<RelationHypothesis> findAll();
@Override
@Query("SELECT COUNT(h) FROM RelationHypothesis h WHERE " + PRIMARY_SCOPE)
long count();
@Override
@Query("SELECT h FROM RelationHypothesis h WHERE h.id = :id AND " + PRIMARY_SCOPE)
Optional<RelationHypothesis> findById(@Param("id") Long id);
@Override
default void deleteAll() {
deleteAll(findAll());
}
@Override
default void deleteAllInBatch() {
deleteAll(findAll());
}
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.status = :status
ORDER BY h.id
""")
List<RelationHypothesis> findByStatus(@Param("status") HypothesisStatus status);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.analysisSessionId = :analysisSessionId
ORDER BY h.id
""")
List<RelationHypothesis> findByAnalysisSessionId(
@Param("analysisSessionId") String analysisSessionId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.sourceNodeId = :sourceNodeId
AND h.targetNodeId = :targetNodeId
AND h.relationType = :relationType
ORDER BY h.id
""")
List<RelationHypothesis> findBySourceNodeIdAndTargetNodeIdAndRelationType(
@Param("sourceNodeId") String sourceNodeId,
@Param("targetNodeId") String targetNodeId,
@Param("relationType") RelationType relationType);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.status IN :statuses
ORDER BY h.id
""")
List<RelationHypothesis> findByStatusIn(
@Param("statuses") List<HypothesisStatus> statuses);
// ── Legacy workspace aliases constrained to the primary repository ──
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.workspaceId = :workspaceId
ORDER BY h.id
""")
List<RelationHypothesis> findByWorkspaceId(
@Param("workspaceId") String workspaceId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.workspaceId IS NULL
ORDER BY h.id
""")
List<RelationHypothesis> findByWorkspaceIdIsNull();
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.status = :status
AND h.workspaceId IS NULL
ORDER BY h.id
""")
List<RelationHypothesis> findByStatusAndWorkspaceIdIsNull(
@Param("status") HypothesisStatus status);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND (h.workspaceId = :workspaceId OR h.workspaceId IS NULL)
ORDER BY h.id
""")
List<RelationHypothesis> findByWorkspaceIdIsNullOrWorkspaceId(
@Param("workspaceId") String workspaceId);
@Query("""
SELECT h FROM RelationHypothesis h
WHERE """ + PRIMARY_SCOPE + """
AND h.status = :status
AND (h.workspaceId = :workspaceId OR h.workspaceId IS NULL)
ORDER BY h.id
""")
List<RelationHypothesis> findByStatusAndWorkspace(
@Param("status") HypothesisStatus status,
@Param("workspaceId") String workspaceId);
}