From 7d8d77f5c987ecc5b8f68e08ea55b75b2ca835fd Mon Sep 17 00:00:00 2001 From: Santeri Korri Date: Fri, 24 Jan 2025 15:08:28 +0200 Subject: [PATCH] OY-798 Migroidaan laskentakaavat jsonb:ksi inkrementaalisesti --- valintaperusteet-domain/pom.xml | 4 ++ .../model/Arvokonvertteriparametri.java | 2 + .../model/Arvovalikonvertteriparametri.java | 2 + .../valintaperusteet/model/BaseEntity.java | 2 + .../model/EntityManagerUtils.java | 16 ++++++ .../model/Funktioargumentti.java | 35 ++++++++++++ .../model/Konvertteriparametri.java | 2 + .../valintaperusteet/model/Laskentakaava.java | 55 +++++++++++++----- .../model/LokalisoituTeksti.java | 2 + .../model/Syoteparametri.java | 2 + .../model/TekstiRyhmaSerializer.java | 21 +++++++ .../model/ValintaperusteViite.java | 5 ++ .../valintaperusteet/model/Valintaryhma.java | 2 + .../vm/sade/service/valintaperusteet/App.java | 2 + .../config/EntityManagerConfiguration.java | 17 ++++++ .../dao/LaskentakaavaDAO.java | 3 + .../dao/impl/JarjestyskriteeriDAOImpl.java | 28 ++++----- .../dao/impl/LaskentakaavaDAOImpl.java | 26 +++++++++ .../LaskentaKaavaMigrationService.java | 57 +++++++++++++++++++ ...800000__add_laskentakaava_jsonb_column.sql | 1 + 20 files changed, 258 insertions(+), 26 deletions(-) create mode 100644 valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/EntityManagerUtils.java create mode 100644 valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/TekstiRyhmaSerializer.java create mode 100644 valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/config/EntityManagerConfiguration.java create mode 100644 valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/service/background/LaskentaKaavaMigrationService.java create mode 100644 valintaperusteet-service/src/main/resources/db/migration/V2025012800000__add_laskentakaava_jsonb_column.sql diff --git a/valintaperusteet-domain/pom.xml b/valintaperusteet-domain/pom.xml index ee1e0fd7..1e1662da 100644 --- a/valintaperusteet-domain/pom.xml +++ b/valintaperusteet-domain/pom.xml @@ -10,6 +10,10 @@ Valintaperusteet :: Domain + + jakarta.persistence + jakarta.persistence-api + org.springframework.boot spring-boot-starter-data-jpa diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvokonvertteriparametri.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvokonvertteriparametri.java index 1d324441..c8aa00bb 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvokonvertteriparametri.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvokonvertteriparametri.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import jakarta.persistence.*; @Entity @@ -14,6 +15,7 @@ public class Arvokonvertteriparametri extends Konvertteriparametri { @JoinColumn(name = "tekstiryhma_id", nullable = true) @ManyToOne(fetch = FetchType.LAZY, optional = true) + @JsonSerialize(using = TekstiRyhmaSerializer.class) private TekstiRyhma kuvaukset; public String getArvo() { diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvovalikonvertteriparametri.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvovalikonvertteriparametri.java index 1cbb80b7..d5e4d3d7 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvovalikonvertteriparametri.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Arvovalikonvertteriparametri.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import jakarta.persistence.*; @Entity @@ -35,6 +36,7 @@ public String toString() { @JoinColumn(name = "tekstiryhma_id", nullable = true) @ManyToOne(fetch = FetchType.LAZY, optional = true) + @JsonSerialize(using = TekstiRyhmaSerializer.class) private TekstiRyhma kuvaukset; public String getMinValue() { diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/BaseEntity.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/BaseEntity.java index d4cd7777..4c8be5ae 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/BaseEntity.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/BaseEntity.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import java.io.Serializable; @@ -13,6 +14,7 @@ public class BaseEntity implements Serializable { @Id @Column(name = ID_COLUMN_NAME, unique = true, nullable = false) @GeneratedValue + @JsonIgnore private Long id; @Version diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/EntityManagerUtils.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/EntityManagerUtils.java new file mode 100644 index 00000000..6533c39f --- /dev/null +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/EntityManagerUtils.java @@ -0,0 +1,16 @@ +package fi.vm.sade.service.valintaperusteet.model; + +import jakarta.persistence.EntityManager; + +public class EntityManagerUtils { + + private static EntityManager em; + + public static void setEntityManager(EntityManager em) { + EntityManagerUtils.em = em; + } + + public static EntityManager getEntityManager() { + return em; + } +} diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Funktioargumentti.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Funktioargumentti.java index 5df7c460..f92398ba 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Funktioargumentti.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Funktioargumentti.java @@ -1,7 +1,17 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import jakarta.persistence.*; import jakarta.validation.constraints.Min; +import java.io.IOException; @Entity @Table(name = "funktioargumentti") @@ -10,6 +20,7 @@ public class Funktioargumentti extends BaseEntity implements Comparable { + + @Override + public void serialize(Laskentakaava value, JsonGenerator gen, SerializerProvider serializers) + throws IOException { + gen.writeNumber(value.getId()); + } + } + + static class CustomLaskentakaavaDeserializer extends JsonDeserializer { + + @Override + public Laskentakaava deserialize(JsonParser p, DeserializationContext ctxt) { + try { + return EntityManagerUtils.getEntityManager() + .find(Laskentakaava.class, p.getNumberValue().longValue()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } } diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Konvertteriparametri.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Konvertteriparametri.java index bbaa4ed8..d0989ab7 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Konvertteriparametri.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Konvertteriparametri.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; @MappedSuperclass @@ -9,6 +10,7 @@ public abstract class Konvertteriparametri extends BaseEntity { @JoinColumn(name = "funktiokutsu_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JsonBackReference private Funktiokutsu funktiokutsu; public String getPaluuarvo() { diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Laskentakaava.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Laskentakaava.java index 34aa13b0..005ecf3a 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Laskentakaava.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Laskentakaava.java @@ -1,21 +1,13 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.*; import fi.vm.sade.service.valintaperusteet.dto.model.Funktiotyyppi; -import jakarta.persistence.Cacheable; -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.PrePersist; -import jakarta.persistence.PreUpdate; -import jakarta.persistence.Table; +import jakarta.persistence.*; import java.util.HashSet; import java.util.Set; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; @Entity @Table(name = "laskentakaava") @@ -56,6 +48,11 @@ public class Laskentakaava extends BaseEntity implements FunktionArgumentti { @OneToMany(fetch = FetchType.LAZY, mappedBy = "laskentakaava", cascade = CascadeType.PERSIST) private Set jarjestyskriteerit = new HashSet(); + @JdbcTypeCode(SqlTypes.JSON) + @Column(columnDefinition = "jsonb") + @Convert(converter = JsonNodeConverter.class) + private Funktiokutsu kaava; + public Boolean getOnLuonnos() { return onLuonnos; } @@ -97,11 +94,15 @@ public void setHakukohde(HakukohdeViite hakukohde) { } public Funktiokutsu getFunktiokutsu() { + if (this.kaava != null) { + return this.kaava; + } return funktiokutsu; } public void setFunktiokutsu(Funktiokutsu funktiokutsu) { this.funktiokutsu = funktiokutsu; + this.kaava = funktiokutsu; } public Funktiotyyppi getTyyppi() { @@ -128,6 +129,10 @@ public void setKopiot(Set kopiot) { this.kopiot = kopiot; } + public void migrateKaava() { + this.kaava = this.funktiokutsu; + } + @Override public Long getId() { return super.getId(); @@ -163,4 +168,28 @@ public Laskentakaava getKopioLaskentakaavasta() { public void setKopioLaskentakaavasta(Laskentakaava kopioLaskentakaavasta) { this.kopioLaskentakaavasta = kopioLaskentakaavasta; } + + @Converter(autoApply = true) + static class JsonNodeConverter implements AttributeConverter { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public String convertToDatabaseColumn(Funktiokutsu funktiokutsu) { + try { + return objectMapper.writeValueAsString(funktiokutsu); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error while serializing JsonNode to JSON", e); + } + } + + @Override + public Funktiokutsu convertToEntityAttribute(String dbData) { + try { + return dbData == null ? null : objectMapper.readValue(dbData, Funktiokutsu.class); + } catch (JsonProcessingException e) { + throw new RuntimeException("Error while deserializing JSON to JsonNode", e); + } + } + } } diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/LokalisoituTeksti.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/LokalisoituTeksti.java index 6e4b6a1d..f45946d7 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/LokalisoituTeksti.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/LokalisoituTeksti.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import fi.vm.sade.service.valintaperusteet.dto.model.Kieli; import jakarta.persistence.*; @@ -19,6 +20,7 @@ public class LokalisoituTeksti extends BaseEntity { @JoinColumn(name = "tekstiryhma_id", nullable = false) @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JsonBackReference private TekstiRyhma ryhma; public String getTeksti() { diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Syoteparametri.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Syoteparametri.java index 9b057102..e393c6ba 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Syoteparametri.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/Syoteparametri.java @@ -1,5 +1,6 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.*; @Entity @@ -14,6 +15,7 @@ public class Syoteparametri extends BaseEntity { @JoinColumn(name = "funktiokutsu_id", nullable = false) @ManyToOne(optional = false) + @JsonBackReference private Funktiokutsu funktiokutsu; public String getAvain() { diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/TekstiRyhmaSerializer.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/TekstiRyhmaSerializer.java new file mode 100644 index 00000000..5d8245b9 --- /dev/null +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/TekstiRyhmaSerializer.java @@ -0,0 +1,21 @@ +package fi.vm.sade.service.valintaperusteet.model; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class TekstiRyhmaSerializer extends JsonSerializer { + + @Override + public void serialize(TekstiRyhma value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + Map map = new HashMap<>(); + map.put("id", value.getId()); + map.put("tekstit", value.getTekstit()); + map.put("version", value.getVersion()); + gen.writeObject(map); + } +} diff --git a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/ValintaperusteViite.java b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/ValintaperusteViite.java index 491f530d..6f5bd1cc 100644 --- a/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/ValintaperusteViite.java +++ b/valintaperusteet-domain/src/main/java/fi/vm/sade/service/valintaperusteet/model/ValintaperusteViite.java @@ -1,5 +1,7 @@ package fi.vm.sade.service.valintaperusteet.model; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import fi.vm.sade.service.valintaperusteet.dto.model.Valintaperustelahde; import jakarta.persistence.*; @@ -28,6 +30,7 @@ public class ValintaperusteViite extends BaseEntity implements Comparable { Laskentakaava getLaskentakaava(Long id); @@ -23,5 +24,7 @@ List findKaavas( String hakukohdeOid, fi.vm.sade.service.valintaperusteet.dto.model.Funktiotyyppi tyyppi); + Optional migrateLaskentakaavat(); + void flush(); } diff --git a/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/JarjestyskriteeriDAOImpl.java b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/JarjestyskriteeriDAOImpl.java index d2e864ff..4196effd 100644 --- a/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/JarjestyskriteeriDAOImpl.java +++ b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/JarjestyskriteeriDAOImpl.java @@ -29,19 +29,21 @@ protected JPAQueryFactory queryFactory() { public List findByJono(String oid) { QJarjestyskriteeri jk = QJarjestyskriteeri.jarjestyskriteeri; QValintatapajono j = QValintatapajono.valintatapajono; - return LinkitettavaJaKopioitavaUtil.jarjesta( - queryFactory() - .selectFrom(jk) - .join(jk.valintatapajono, j) - .fetchJoin() - .leftJoin(jk.edellinen) - .fetchJoin() - .leftJoin(jk.master) - .fetchJoin() - .leftJoin(jk.laskentakaava) - .fetchJoin() - .where(j.oid.eq(oid)) - .fetch()); + List kriteerit = + LinkitettavaJaKopioitavaUtil.jarjesta( + queryFactory() + .selectFrom(jk) + .join(jk.valintatapajono, j) + .fetchJoin() + .leftJoin(jk.edellinen) + .fetchJoin() + .leftJoin(jk.master) + .fetchJoin() + .leftJoin(jk.laskentakaava) + .fetchJoin() + .where(j.oid.eq(oid)) + .fetch()); + return kriteerit; } @Override diff --git a/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/LaskentakaavaDAOImpl.java b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/LaskentakaavaDAOImpl.java index 3201e973..d58de290 100644 --- a/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/LaskentakaavaDAOImpl.java +++ b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/dao/impl/LaskentakaavaDAOImpl.java @@ -8,12 +8,23 @@ import fi.vm.sade.service.valintaperusteet.dao.LaskentakaavaDAO; import fi.vm.sade.service.valintaperusteet.dto.model.Funktiotyyppi; import fi.vm.sade.service.valintaperusteet.model.*; +import jakarta.persistence.EntityManager; + +import java.util.Collection; import java.util.List; +import java.util.Optional; + +import jakarta.persistence.LockModeType; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository public class LaskentakaavaDAOImpl extends AbstractJpaDAOImpl implements LaskentakaavaDAO { + + @Autowired EntityManager em; + @Override public Laskentakaava getLaskentakaava(Long id) { QLaskentakaava lk = QLaskentakaava.laskentakaava; @@ -92,4 +103,19 @@ protected JPAQueryFactory queryFactory() { public void flush() { getEntityManager().flush(); } + + @Override + @Transactional + public Optional migrateLaskentakaavat() { + QLaskentakaava lk = QLaskentakaava.laskentakaava; + Collection laskentakaavat = + queryFactory().selectFrom(lk).where(lk.kaava.isNull()).setLockMode(LockModeType.PESSIMISTIC_WRITE).setHint("jakarta.persistence.lock.timeout", -2).limit(1).fetch(); + if(laskentakaavat.size()==0) { + return Optional.empty(); + } + laskentakaavat.forEach( + kaava -> kaava.migrateKaava()); + + return Optional.of(laskentakaavat.iterator().next().getId()); + } } diff --git a/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/service/background/LaskentaKaavaMigrationService.java b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/service/background/LaskentaKaavaMigrationService.java new file mode 100644 index 00000000..7f81240b --- /dev/null +++ b/valintaperusteet-service/src/main/java/fi/vm/sade/service/valintaperusteet/service/background/LaskentaKaavaMigrationService.java @@ -0,0 +1,57 @@ +package fi.vm.sade.service.valintaperusteet.service.background; + +import fi.vm.sade.service.valintaperusteet.dao.LaskentakaavaDAO; +import fi.vm.sade.service.valintaperusteet.dto.mapping.ValintaperusteetModelMapper; +import fi.vm.sade.service.valintaperusteet.service.LaskentakaavaService; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.IntStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionTemplate; + +@Component +public class LaskentaKaavaMigrationService implements InitializingBean { + + private static final Logger LOG = LoggerFactory.getLogger(LaskentaKaavaMigrationService.class); + + @Autowired private LaskentakaavaService laskentakaavaService; + + @Autowired private LaskentakaavaDAO laskentakaavaDAO; + + @Autowired private ValintaperusteetModelMapper modelMapper; + + @Autowired private TransactionTemplate transactionTemplate; + + private static final int RINNAKKAISUUS = 10; + + private ExecutorService executor = Executors.newWorkStealingPool(RINNAKKAISUUS); + + @Override + public void afterPropertiesSet() { + IntStream.range(0, RINNAKKAISUUS).mapToObj(i -> executor.submit(() -> { + while(true) { + try { + Instant start = Instant.now(); + Optional id = laskentakaavaDAO.migrateLaskentakaavat(); + if(id.isEmpty()) { + LOG.warn( + "No kaavas to migrate, exiting"); + return; + } + LOG.warn( + "Saved laskentakaava for id: " + id.get() + ", duration: " + Duration.between(start, Instant.now()).toMillis()); + } catch(Exception e) { + LOG.error("Error during laskentakaava migration", e); + } + } + })).toList(); + } +} diff --git a/valintaperusteet-service/src/main/resources/db/migration/V2025012800000__add_laskentakaava_jsonb_column.sql b/valintaperusteet-service/src/main/resources/db/migration/V2025012800000__add_laskentakaava_jsonb_column.sql new file mode 100644 index 00000000..64aca053 --- /dev/null +++ b/valintaperusteet-service/src/main/resources/db/migration/V2025012800000__add_laskentakaava_jsonb_column.sql @@ -0,0 +1 @@ +ALTER TABLE laskentakaava ADD COLUMN IF NOT EXISTS kaava jsonb;