feat(election): committee management — CRUD, members, image, and director fix
- Add Committee entity, CommitteeMember, repositories, service, and REST API - Liquibase migrations: 0349 committee tables, 0350 committee image column - Committee supports profile image (base64 TEXT), name, description, status - Current directors: fix EclipseLink native query (?1 positional param) and add fallback to most recent RESULT_DECLARED election when no active duration found - DirectorAppointmentRepository: add findByElectionIdAndStatus (non-pageable) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
00d3a2e333
commit
2606427203
+71
@@ -0,0 +1,71 @@
|
||||
package org.apache.fineract.portfolio.election.api;
|
||||
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeRequest;
|
||||
import org.apache.fineract.portfolio.election.service.CommitteeService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Path("/v1/election/committees")
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public class CommitteeApiResource {
|
||||
|
||||
private final CommitteeService committeeService;
|
||||
|
||||
@GET
|
||||
public Response getAll() {
|
||||
return Response.ok(committeeService.retrieveAll()).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
public Response getOne(@PathParam("id") Long id) {
|
||||
return Response.ok(committeeService.retrieveOne(id)).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/current-directors")
|
||||
public Response getCurrentDirectors() {
|
||||
return Response.ok(committeeService.getCurrentElectionDirectors()).build();
|
||||
}
|
||||
|
||||
@POST
|
||||
public Response create(CommitteeRequest request) {
|
||||
return Response.ok(committeeService.createCommittee(request)).build();
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
public Response update(@PathParam("id") Long id, CommitteeRequest request) {
|
||||
return Response.ok(committeeService.updateCommittee(id, request)).build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{id}/members")
|
||||
public Response addMembers(@PathParam("id") Long id, Map<String, List<Long>> body) {
|
||||
List<Long> ids = body.get("directorAppointmentIds");
|
||||
return Response.ok(committeeService.addMembers(id, ids)).build();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}/members/{directorAppointmentId}")
|
||||
public Response removeMember(@PathParam("id") Long id,
|
||||
@PathParam("directorAppointmentId") Long directorAppointmentId) {
|
||||
return Response.ok(committeeService.removeMember(id, directorAppointmentId)).build();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/{id}/dissolve")
|
||||
public Response dissolve(@PathParam("id") Long id) {
|
||||
committeeService.dissolveCommittee(id);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.apache.fineract.portfolio.election.data;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class CommitteeData {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String description;
|
||||
private String status;
|
||||
private String image;
|
||||
private OffsetDateTime createdDate;
|
||||
private Long createdBy;
|
||||
private OffsetDateTime lastModifiedDate;
|
||||
private Long lastModifiedBy;
|
||||
private List<CommitteeMemberData> members;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.apache.fineract.portfolio.election.data;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class CommitteeMemberData {
|
||||
private Long id;
|
||||
private Long directorAppointmentId;
|
||||
private String candidateName;
|
||||
private String designation;
|
||||
private String postName;
|
||||
private Long memberId;
|
||||
private LocalDate addedDate;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package org.apache.fineract.portfolio.election.data;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CommitteeRequest {
|
||||
private String name;
|
||||
private String description;
|
||||
private String image;
|
||||
private List<Long> directorAppointmentIds;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.apache.fineract.portfolio.election.domain;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_election_committee")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class Committee extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
|
||||
@Column(name = "name", nullable = false, length = 200)
|
||||
private String name;
|
||||
|
||||
@Column(name = "image", columnDefinition = "TEXT")
|
||||
private String image;
|
||||
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "status", nullable = false, length = 30)
|
||||
private CommitteeStatus status = CommitteeStatus.ACTIVE;
|
||||
|
||||
@OneToMany(mappedBy = "committee", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private List<CommitteeMember> members = new ArrayList<>();
|
||||
|
||||
public static Committee create(String name, String description) {
|
||||
Committee c = new Committee();
|
||||
c.name = name;
|
||||
c.description = description;
|
||||
c.status = CommitteeStatus.ACTIVE;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.apache.fineract.portfolio.election.domain;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_election_committee_member")
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class CommitteeMember {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "committee_id", nullable = false)
|
||||
private Committee committee;
|
||||
|
||||
@Column(name = "director_appointment_id", nullable = false)
|
||||
private Long directorAppointmentId;
|
||||
|
||||
@Column(name = "added_date", nullable = false)
|
||||
private LocalDate addedDate = LocalDate.now();
|
||||
|
||||
public static CommitteeMember create(Committee committee, Long directorAppointmentId) {
|
||||
CommitteeMember m = new CommitteeMember();
|
||||
m.committee = committee;
|
||||
m.directorAppointmentId = directorAppointmentId;
|
||||
m.addedDate = LocalDate.now();
|
||||
return m;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package org.apache.fineract.portfolio.election.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CommitteeMemberRepository extends JpaRepository<CommitteeMember, Long> {
|
||||
|
||||
List<CommitteeMember> findByCommitteeId(Long committeeId);
|
||||
|
||||
boolean existsByCommitteeIdAndDirectorAppointmentId(Long committeeId, Long directorAppointmentId);
|
||||
|
||||
void deleteByCommitteeIdAndDirectorAppointmentId(Long committeeId, Long directorAppointmentId);
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.apache.fineract.portfolio.election.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CommitteeRepository extends JpaRepository<Committee, Long> {
|
||||
|
||||
List<Committee> findAllByOrderByCreatedDateDesc();
|
||||
|
||||
List<Committee> findByStatusOrderByCreatedDateDesc(CommitteeStatus status);
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package org.apache.fineract.portfolio.election.domain;
|
||||
|
||||
public enum CommitteeStatus {
|
||||
ACTIVE, DISSOLVED
|
||||
}
|
||||
+2
@@ -22,6 +22,8 @@ public interface DirectorAppointmentRepository extends JpaRepository<DirectorApp
|
||||
|
||||
Page<DirectorAppointment> findByElectionIdAndStatus(Long electionId, DirectorAppointmentStatus status, Pageable pageable);
|
||||
|
||||
List<DirectorAppointment> findByElectionIdAndStatus(Long electionId, DirectorAppointmentStatus status);
|
||||
|
||||
List<DirectorAppointment> findByElectionIdAndCandidateId(Long electionId, Long candidateId);
|
||||
|
||||
boolean existsByElectionIdAndCandidateId(Long electionId, Long candidateId);
|
||||
|
||||
+2
-2
@@ -36,6 +36,6 @@ public interface ElectionConfigRepository extends JpaRepository<ElectionConfig,
|
||||
|
||||
boolean existsByStatusIn(Set<ElectionStatus> statuses);
|
||||
|
||||
@Query(value = "SELECT * FROM m_election_config WHERE status = 'RESULT_DECLARED' AND duration_years IS NOT NULL AND election_date + (duration_years || ' years')::interval > :today LIMIT 1", nativeQuery = true)
|
||||
Optional<ElectionConfig> findFirstWithActiveDuration(@Param("today") LocalDate today);
|
||||
@Query(value = "SELECT * FROM m_election_config WHERE status = 'RESULT_DECLARED' AND duration_years IS NOT NULL AND election_date + CAST(duration_years || ' years' AS INTERVAL) > ?1 LIMIT 1", nativeQuery = true)
|
||||
Optional<ElectionConfig> findFirstWithActiveDuration(LocalDate today);
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.apache.fineract.portfolio.election.service;
|
||||
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeData;
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeRequest;
|
||||
import org.apache.fineract.portfolio.election.data.DirectorAppointmentData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommitteeService {
|
||||
|
||||
CommitteeData createCommittee(CommitteeRequest request);
|
||||
|
||||
CommitteeData updateCommittee(Long id, CommitteeRequest request);
|
||||
|
||||
void dissolveCommittee(Long id);
|
||||
|
||||
List<CommitteeData> retrieveAll();
|
||||
|
||||
CommitteeData retrieveOne(Long id);
|
||||
|
||||
CommitteeData addMembers(Long committeeId, List<Long> directorAppointmentIds);
|
||||
|
||||
CommitteeData removeMember(Long committeeId, Long directorAppointmentId);
|
||||
|
||||
List<DirectorAppointmentData> getCurrentElectionDirectors();
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package org.apache.fineract.portfolio.election.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeData;
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeMemberData;
|
||||
import org.apache.fineract.portfolio.election.data.CommitteeRequest;
|
||||
import org.apache.fineract.portfolio.election.data.DirectorAppointmentData;
|
||||
import org.apache.fineract.portfolio.election.domain.Committee;
|
||||
import org.apache.fineract.portfolio.election.domain.CommitteeMember;
|
||||
import org.apache.fineract.portfolio.election.domain.CommitteeMemberRepository;
|
||||
import org.apache.fineract.portfolio.election.domain.CommitteeRepository;
|
||||
import org.apache.fineract.portfolio.election.domain.CommitteeStatus;
|
||||
import org.apache.fineract.portfolio.election.domain.DirectorAppointment;
|
||||
import org.apache.fineract.portfolio.election.domain.DirectorAppointmentRepository;
|
||||
import org.apache.fineract.portfolio.election.domain.DirectorAppointmentStatus;
|
||||
import org.apache.fineract.portfolio.election.domain.ElectionCandidateRepository;
|
||||
import org.apache.fineract.portfolio.election.domain.ElectionConfigRepository;
|
||||
import org.apache.fineract.portfolio.election.domain.ElectionStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommitteeServiceImpl implements CommitteeService {
|
||||
|
||||
private final CommitteeRepository committeeRepository;
|
||||
private final CommitteeMemberRepository memberRepository;
|
||||
private final DirectorAppointmentRepository directorRepository;
|
||||
private final ElectionCandidateRepository candidateRepository;
|
||||
private final ElectionConfigRepository electionConfigRepository;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CommitteeData createCommittee(CommitteeRequest request) {
|
||||
Committee committee = Committee.create(request.getName(), request.getDescription());
|
||||
committee.setImage(request.getImage());
|
||||
committeeRepository.save(committee);
|
||||
|
||||
if (request.getDirectorAppointmentIds() != null) {
|
||||
for (Long dirId : request.getDirectorAppointmentIds()) {
|
||||
if (!memberRepository.existsByCommitteeIdAndDirectorAppointmentId(committee.getId(), dirId)) {
|
||||
committee.getMembers().add(CommitteeMember.create(committee, dirId));
|
||||
}
|
||||
}
|
||||
committeeRepository.save(committee);
|
||||
}
|
||||
return toData(committee);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CommitteeData updateCommittee(Long id, CommitteeRequest request) {
|
||||
Committee committee = findOrThrow(id);
|
||||
if (request.getName() != null) committee.setName(request.getName());
|
||||
if (request.getDescription() != null) committee.setDescription(request.getDescription());
|
||||
committee.setImage(request.getImage());
|
||||
return toData(committeeRepository.save(committee));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void dissolveCommittee(Long id) {
|
||||
Committee committee = findOrThrow(id);
|
||||
committee.setStatus(CommitteeStatus.DISSOLVED);
|
||||
committeeRepository.save(committee);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommitteeData> retrieveAll() {
|
||||
return committeeRepository.findAllByOrderByCreatedDateDesc()
|
||||
.stream().map(this::toData).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommitteeData retrieveOne(Long id) {
|
||||
return toData(findOrThrow(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CommitteeData addMembers(Long committeeId, List<Long> directorAppointmentIds) {
|
||||
Committee committee = findOrThrow(committeeId);
|
||||
for (Long dirId : directorAppointmentIds) {
|
||||
if (!memberRepository.existsByCommitteeIdAndDirectorAppointmentId(committeeId, dirId)) {
|
||||
committee.getMembers().add(CommitteeMember.create(committee, dirId));
|
||||
}
|
||||
}
|
||||
return toData(committeeRepository.save(committee));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CommitteeData removeMember(Long committeeId, Long directorAppointmentId) {
|
||||
findOrThrow(committeeId);
|
||||
memberRepository.deleteByCommitteeIdAndDirectorAppointmentId(committeeId, directorAppointmentId);
|
||||
return toData(findOrThrow(committeeId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DirectorAppointmentData> getCurrentElectionDirectors() {
|
||||
var currentElection = electionConfigRepository.findFirstWithActiveDuration(LocalDate.now());
|
||||
|
||||
// fallback: most recent RESULT_DECLARED election if none has active duration
|
||||
if (currentElection.isEmpty()) {
|
||||
currentElection = electionConfigRepository
|
||||
.findByStatus(ElectionStatus.RESULT_DECLARED)
|
||||
.stream()
|
||||
.max(Comparator.comparing(e -> e.getElectionDate() != null ? e.getElectionDate() : LocalDate.MIN));
|
||||
}
|
||||
|
||||
if (currentElection.isEmpty()) return List.of();
|
||||
|
||||
Long electionId = currentElection.get().getId();
|
||||
List<DirectorAppointment> directors = directorRepository
|
||||
.findByElectionIdAndStatus(electionId, DirectorAppointmentStatus.ACTIVE);
|
||||
|
||||
Set<Long> candidateIds = directors.stream()
|
||||
.map(DirectorAppointment::getCandidateId).collect(Collectors.toSet());
|
||||
Map<Long, Long> candidateMemberMap = candidateRepository.findAllById(candidateIds)
|
||||
.stream()
|
||||
.filter(c -> c.getNomination() != null && c.getNomination().getMemberId() != null)
|
||||
.collect(Collectors.toMap(c -> c.getId(), c -> c.getNomination().getMemberId()));
|
||||
|
||||
return directors.stream().map(d -> DirectorAppointmentData.builder()
|
||||
.id(d.getId())
|
||||
.candidateName(d.getCandidateName())
|
||||
.designation(d.getDesignation())
|
||||
.postName(d.getPostName())
|
||||
.memberId(candidateMemberMap.get(d.getCandidateId()))
|
||||
.build()).toList();
|
||||
}
|
||||
|
||||
private Committee findOrThrow(Long id) {
|
||||
return committeeRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("Committee not found: " + id));
|
||||
}
|
||||
|
||||
private CommitteeData toData(Committee c) {
|
||||
List<Long> dirIds = c.getMembers().stream()
|
||||
.map(CommitteeMember::getDirectorAppointmentId).toList();
|
||||
|
||||
Map<Long, DirectorAppointment> dirMap = directorRepository.findAllById(dirIds)
|
||||
.stream().collect(Collectors.toMap(DirectorAppointment::getId, d -> d));
|
||||
|
||||
Set<Long> candidateIds = dirMap.values().stream()
|
||||
.map(DirectorAppointment::getCandidateId).collect(Collectors.toSet());
|
||||
Map<Long, Long> candidateMemberMap = candidateRepository.findAllById(candidateIds)
|
||||
.stream()
|
||||
.filter(e -> e.getNomination() != null && e.getNomination().getMemberId() != null)
|
||||
.collect(Collectors.toMap(e -> e.getId(), e -> e.getNomination().getMemberId()));
|
||||
|
||||
List<CommitteeMemberData> members = c.getMembers().stream().map(m -> {
|
||||
DirectorAppointment dir = dirMap.get(m.getDirectorAppointmentId());
|
||||
return CommitteeMemberData.builder()
|
||||
.id(m.getId())
|
||||
.directorAppointmentId(m.getDirectorAppointmentId())
|
||||
.candidateName(dir != null ? dir.getCandidateName() : null)
|
||||
.designation(dir != null ? dir.getDesignation() : null)
|
||||
.postName(dir != null ? dir.getPostName() : null)
|
||||
.memberId(dir != null ? candidateMemberMap.get(dir.getCandidateId()) : null)
|
||||
.addedDate(m.getAddedDate())
|
||||
.build();
|
||||
}).toList();
|
||||
|
||||
return CommitteeData.builder()
|
||||
.id(c.getId())
|
||||
.name(c.getName())
|
||||
.description(c.getDescription())
|
||||
.status(c.getStatus().name())
|
||||
.image(c.getImage())
|
||||
.createdDate(c.getCreatedDate().orElse(null))
|
||||
.createdBy(c.getCreatedBy().orElse(null))
|
||||
.lastModifiedDate(c.getLastModifiedDate().orElse(null))
|
||||
.lastModifiedBy(c.getLastModifiedBy().orElse(null))
|
||||
.members(members)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -376,4 +376,6 @@
|
||||
<include file="parts/0346_election_audit_log_description_to_text.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0347_election_director_appointment.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0348_election_config_duration_years.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0349_election_committee.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0350_committee_image.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
|
||||
<changeSet id="0349-election-committee" author="CBS">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><tableExists tableName="m_election_committee"/></not>
|
||||
</preConditions>
|
||||
|
||||
<createTable tableName="m_election_committee">
|
||||
<column name="id" type="BIGSERIAL" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="name" type="VARCHAR(200)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="description" type="TEXT"/>
|
||||
<column name="status" type="VARCHAR(30)" defaultValue="ACTIVE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created_by" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="last_modified_by" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<createTable tableName="m_election_committee_member">
|
||||
<column name="id" type="BIGSERIAL" autoIncrement="true">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="committee_id" type="BIGINT">
|
||||
<constraints nullable="false"
|
||||
foreignKeyName="fk_committee_member_committee"
|
||||
references="m_election_committee(id)"/>
|
||||
</column>
|
||||
<column name="director_appointment_id" type="BIGINT">
|
||||
<constraints nullable="false"
|
||||
foreignKeyName="fk_committee_member_director"
|
||||
references="m_election_director_appointment(id)"/>
|
||||
</column>
|
||||
<column name="added_date" type="DATE" defaultValueComputed="CURRENT_DATE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<createIndex indexName="idx_committee_member_committee"
|
||||
tableName="m_election_committee_member">
|
||||
<column name="committee_id"/>
|
||||
</createIndex>
|
||||
|
||||
<createIndex indexName="idx_committee_status"
|
||||
tableName="m_election_committee">
|
||||
<column name="status"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
|
||||
<changeSet id="0350-committee-image" author="CBS">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<not><columnExists tableName="m_election_committee" columnName="image"/></not>
|
||||
</preConditions>
|
||||
<addColumn tableName="m_election_committee">
|
||||
<column name="image" type="TEXT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user