From f005cc5494310055dce898d27f786668defa5f9d Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 09:51:46 +0000 Subject: [PATCH 01/20] Enable MS SQL Server as Emap target and give ability to switch between dialects. Also use docker compose profiles to turn containers on and off. --- core/core-config-envs.EXAMPLE | 1 + core/docker-compose.fakeuds.yml | 19 ++++++++++ core/fakeuds-mssql-config-envs.EXAMPLE | 1 + core/pom.xml | 5 +++ .../src/main/resources/application.properties | 4 +-- .../emap_runner/docker/docker_runner.py | 36 +++++++++++++------ emap-setup/emap_runner/global_config.py | 1 + emap-setup/global-configuration-EXAMPLE.yaml | 6 ++++ 8 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 core/fakeuds-mssql-config-envs.EXAMPLE diff --git a/core/core-config-envs.EXAMPLE b/core/core-config-envs.EXAMPLE index f248f737d..fe98b8eaf 100644 --- a/core/core-config-envs.EXAMPLE +++ b/core/core-config-envs.EXAMPLE @@ -9,6 +9,7 @@ UDS_JDBC_URL=jdbc:postgresql://host.docker.internal:5432/informdb UDS_SCHEMA=public UDS_USERNAME=postgres UDS_PASSWORD=postgres +UDS_HIBERNATE_DIALECT= SPRING_RABBITMQ_HOST=rabbitmq SPRING_RABBITMQ_PORT=5672 SPRING_RABBITMQ_USERNAME=emap diff --git a/core/docker-compose.fakeuds.yml b/core/docker-compose.fakeuds.yml index cd10aaafc..9d28e787f 100644 --- a/core/docker-compose.fakeuds.yml +++ b/core/docker-compose.fakeuds.yml @@ -12,6 +12,25 @@ services: restart: unless-stopped ports: - "${FAKEUDS_PORT}:5432" + profiles: + - fakeuds-pg + fakeuds-mssql: + image: mcr.microsoft.com/mssql/server:2022-CU17-ubuntu-22.04 + env_file: + - ../../config/fakeuds-mssql-config-envs + environment: + ACCEPT_EULA: "Y" + MSSQL_PID: "Express" + TZ: "Europe/London" + volumes: + - mssql-data-fakeuds:/var/opt/mssql + restart: unless-stopped + ports: + - "${FAKEUDS_MSSQL_PORT}:1433" + profiles: + - fakeuds-mssql + volumes: postgres-data-fakeuds: + mssql-data-fakeuds: diff --git a/core/fakeuds-mssql-config-envs.EXAMPLE b/core/fakeuds-mssql-config-envs.EXAMPLE new file mode 100644 index 000000000..47a10fcd3 --- /dev/null +++ b/core/fakeuds-mssql-config-envs.EXAMPLE @@ -0,0 +1 @@ +MSSQL_SA_PASSWORD= diff --git a/core/pom.xml b/core/pom.xml index fab9e5190..25b342956 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -85,6 +85,11 @@ commons-lang3 + + com.microsoft.sqlserver + mssql-jdbc + + org.postgresql diff --git a/core/src/main/resources/application.properties b/core/src/main/resources/application.properties index c54db3790..b5334a2d2 100644 --- a/core/src/main/resources/application.properties +++ b/core/src/main/resources/application.properties @@ -2,11 +2,11 @@ spring.datasource.url=${UDS_JDBC_URL} spring.datasource.username=${UDS_USERNAME} spring.datasource.password=${UDS_PASSWORD} -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.dialect = ${UDS_HIBERNATE_DIALECT} spring.jpa.properties.hibernate.default_schema=${UDS_SCHEMA} spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect +spring.jpa.database-platform=${UDS_HIBERNATE_DIALECT} spring.jpa.hibernate.ddl-auto = update spring.jpa.show_sql=false spring.datasource.hikari.maximum-pool-size=2 diff --git a/emap-setup/emap_runner/docker/docker_runner.py b/emap-setup/emap_runner/docker/docker_runner.py index 6c231867a..58aba635d 100644 --- a/emap-setup/emap_runner/docker/docker_runner.py +++ b/emap-setup/emap_runner/docker/docker_runner.py @@ -37,6 +37,7 @@ def __init__(self, self.enable_waveform = first_not_none(enable_waveform, self.config.get("waveform", "enable_waveform")) self.use_fake_waveform = first_not_none(use_fake_waveform, self.config.get("waveform", "enable_waveform_generator")) self.use_fake_uds = first_not_none(use_fake_uds, self.config.get("fake_uds", "enable_fake_uds")) + self.use_fake_mssql = self.config.get("fake_mssql", "enable_fake_mssql") def run( self, @@ -55,7 +56,7 @@ def run( self._check_paths_exist() - cmd = self.base_docker_compose_command.split() + cmd = self.base_docker_compose_command for arg in docker_compose_args: cmd += [x.strip('"') for x in arg.split()] @@ -84,15 +85,30 @@ def run( return None @property - def base_docker_compose_command(self) -> str: - return ( - "docker compose -f " - + " -f ".join(str(p) for p in self.docker_compose_paths) - + f' -p {self.config["EMAP_PROJECT_NAME"]} ' - ) + def base_docker_compose_command(self) -> list[str]: + cmd = ["docker", "compose"] + for p in self.docker_compose_file_paths: + cmd.extend(["-f", str(p)]) + for pr in self.docker_compose_profiles: + cmd.extend(["--profile", str(pr)]) + cmd.extend(["-p", self.config["EMAP_PROJECT_NAME"]]) + return cmd + + @property + def docker_compose_profiles(self) -> List[str]: + """Required Docker Compose profiles""" + profiles = [] + if self.use_fake_uds and self.use_fake_mssql: + raise RuntimeError("cannot have both fake postgres and fake MSSQL") + elif self.use_fake_mssql: + profiles.append("fakeuds-mssql") + elif self.use_fake_uds: + profiles.append("fakeuds-pg") + + return profiles @property - def docker_compose_paths(self) -> List[Path]: + def docker_compose_file_paths(self) -> List[Path]: """Paths of all the required docker-compose yamls""" paths = [ @@ -102,7 +118,7 @@ def docker_compose_paths(self) -> List[Path]: # Fakes are for testing only. Waveform is a real feature that is currently off # by default, except for the waveform generator which is for testing waveform # data only. - if self.use_fake_uds: + if self.use_fake_uds or self.use_fake_mssql: paths.append(Path(self.emap_dir, "core", "docker-compose.fakeuds.yml")) if self.enable_waveform: paths.append(Path(self.emap_dir, "waveform-reader", "docker-compose.yml")) @@ -145,7 +161,7 @@ def setup_glowroot_password(self) -> None: def _check_paths_exist(self) -> None: """Ensure all the docker compose files exist""" - paths = self.docker_compose_paths + paths = self.docker_compose_file_paths if not all(path.exists() for path in paths): _paths_str = "\n".join(str(p) for p in paths) diff --git a/emap-setup/emap_runner/global_config.py b/emap-setup/emap_runner/global_config.py index b1ce8e770..7fce97b4c 100644 --- a/emap-setup/emap_runner/global_config.py +++ b/emap-setup/emap_runner/global_config.py @@ -22,6 +22,7 @@ class GlobalConfiguration(dict): "glowroot", "common", "fake_uds", + "fake_mssql", "waveform", "monitoring", ) diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index 3ec419845..6e3caa0e6 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -82,6 +82,7 @@ dates: # Configurations for the UDS. uds: UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds + UDS_HIBERNATE_DIALECT: org.hibernate.dialect.PostgreSQL95Dialect UDS_SCHEMA: schemaname UDS_USERNAME: schemauser UDS_PASSWORD: schemapw @@ -98,6 +99,11 @@ glowroot: fake_uds: enable_fake_uds: false +# Emap in MSSQL +fake_mssql: + enable_fake_mssql: false + MSSQL_SA_PASSWORD: your_password + # config related to waveform data ingress waveform: enable_waveform: false From 203fcafc118e327587a184ea4d945325f086427a Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 09:52:52 +0000 Subject: [PATCH 02/20] Make cassandra settings configurable from global config --- emap-setup/global-configuration-EXAMPLE.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index 6e3caa0e6..b9b01218a 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -94,6 +94,9 @@ glowroot: GLOWROOT_USERNAME: glowrootuser GLOWROOT_PASSWORD: glowrootpw GLOWROOT_ADMIN_PORT: 4000 + MAX_HEAP_SIZE: 4G + HEAP_NEWSIZE: 800M + # For testing outside the GAE, you can enable a fake UDS fake_uds: From 6570104e3d3b23b6d6b6db26c32a34dd5cb9cb09 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 10:23:18 +0000 Subject: [PATCH 03/20] Remove manual type "timestamp with time zone" on all Instant fields, as this is Postgres-specific. --- emap-star/README.md | 5 +++-- .../java/uk/ac/ucl/rits/inform/informdb/AuditCore.java | 10 +++------- .../uk/ac/ucl/rits/inform/informdb/TemporalCore.java | 4 ++-- .../inform/informdb/conditions/PatientCondition.java | 2 -- .../inform/informdb/consults/ConsultationRequest.java | 2 -- .../inform/informdb/decisions/AdvanceDecision.java | 2 -- .../inform/informdb/demographics/CoreDemographic.java | 3 --- .../uk/ac/ucl/rits/inform/informdb/forms/Form.java | 1 - .../ac/ucl/rits/inform/informdb/forms/FormAnswer.java | 2 -- .../rits/inform/informdb/identity/HospitalVisit.java | 3 --- .../uk/ac/ucl/rits/inform/informdb/identity/Mrn.java | 2 +- .../uk/ac/ucl/rits/inform/informdb/labs/LabOrder.java | 2 -- .../uk/ac/ucl/rits/inform/informdb/labs/LabResult.java | 1 - .../uk/ac/ucl/rits/inform/informdb/labs/LabSample.java | 2 -- .../ucl/rits/inform/informdb/labs/LabSensitivity.java | 2 -- .../rits/inform/informdb/movement/LocationVisit.java | 2 -- .../rits/inform/informdb/movement/PlannedMovement.java | 3 --- .../ucl/rits/inform/informdb/questions/Question.java | 4 ++-- .../informdb/visit_recordings/VisitObservation.java | 2 +- .../visit_recordings/VisitObservationType.java | 1 - .../inform/informdb/visit_recordings/Waveform.java | 2 +- .../ucl/rits/inform/datasources/ids/IdsProgress.java | 3 --- 22 files changed, 13 insertions(+), 47 deletions(-) diff --git a/emap-star/README.md b/emap-star/README.md index ed7e89515..2149a2106 100644 --- a/emap-star/README.md +++ b/emap-star/README.md @@ -73,7 +73,8 @@ relational database. We have chosen a relational structure for ease of use and e ``` - Timestamps (date and times) are timezone aware (and automated testing enforces this) and named in the form `Datetime` - Dates should only have date information and be named in the form `Date` +- `timestamp with time zone` is Postgres-specific so should not be specified manually. Hibernate does the right thing in this case. ```java - @Column(columnDefinition = "timestamp with time zone") - private Instant admissionTime; + private Instant admissionDatetime; + private LocalDate addedDate; ``` diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/AuditCore.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/AuditCore.java index 93a90518f..786da6eae 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/AuditCore.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/AuditCore.java @@ -1,14 +1,12 @@ package uk.ac.ucl.rits.inform.informdb; -import java.time.Instant; - -import javax.persistence.Column; -import javax.persistence.MappedSuperclass; - import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import javax.persistence.MappedSuperclass; +import java.time.Instant; + /** * This models the core temporal until values for an audit table. *

@@ -29,9 +27,7 @@ @MappedSuperclass public abstract class AuditCore> extends TemporalCore { - @Column(columnDefinition = "timestamp with time zone") private Instant validUntil; - @Column(columnDefinition = "timestamp with time zone") private Instant storedUntil; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/TemporalCore.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/TemporalCore.java index 8a4d313a8..125d60541 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/TemporalCore.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/TemporalCore.java @@ -26,9 +26,9 @@ @MappedSuperclass public abstract class TemporalCore, A extends AuditCore> implements Serializable { - @Column(nullable = false, columnDefinition = "timestamp with time zone") + @Column(nullable = false) private Instant validFrom; - @Column(nullable = false, columnDefinition = "timestamp with time zone") + @Column(nullable = false) private Instant storedFrom; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java index 6340ccd7a..4b30e6f7e 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java @@ -84,7 +84,6 @@ public class PatientCondition extends TemporalCore { /** * \brief datetime the form was first filed. */ - @Column(columnDefinition = "timestamp with time zone") private Instant firstFiledDatetime; @ToString.Exclude diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormAnswer.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormAnswer.java index b8167ec8b..8cc18d2d1 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormAnswer.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormAnswer.java @@ -59,7 +59,6 @@ public class FormAnswer extends TemporalCore { * \brief The datetime this answer was filed. It may differ from Form.firstFiledDatetime * if this form answer has been updated since the form was first filed. */ - @Column(columnDefinition = "timestamp with time zone") private Instant filedDatetime; /** @@ -94,7 +93,6 @@ public class FormAnswer extends TemporalCore { * \brief Current value of the form if it's a timestamp, else null. * . */ - @Column(columnDefinition = "timestamp with time zone") private Instant valueAsDatetime; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/HospitalVisit.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/HospitalVisit.java index a061eb819..c713a3f7c 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/HospitalVisit.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/HospitalVisit.java @@ -70,7 +70,6 @@ public class HospitalVisit extends TemporalCore { /** * \brief Date and time at which this labOrder was actioned. */ - @Column(columnDefinition = "timestamp with time zone") private Instant orderDatetime; /** * \brief Date and time at which this labOrder was requested. */ - @Column(columnDefinition = "timestamp with time zone") private Instant requestDatetime; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java index f58c9e7d0..8ce531d44 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java @@ -64,7 +64,6 @@ public class LabResult extends TemporalCore { /** * \brief Date and time at which the labResult was last modified. */ - @Column(columnDefinition = "timestamp with time zone") private Instant resultLastModifiedDatetime; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java index 6bf91d648..10e675d53 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java @@ -59,7 +59,6 @@ public class LabSample extends TemporalCore { * * where there test was being performed. */ - @Column(columnDefinition = "timestamp with time zone") private Instant receiptAtLabDatetime; /** @@ -67,7 +66,6 @@ public class LabSample extends TemporalCore { * * (e.g. time of phlebotomy). */ - @Column(columnDefinition = "timestamp with time zone") private Instant sampleCollectionDatetime; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSensitivity.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSensitivity.java index 3abb61dd5..c9f1dea06 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSensitivity.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSensitivity.java @@ -6,7 +6,6 @@ import uk.ac.ucl.rits.inform.informdb.TemporalCore; import uk.ac.ucl.rits.inform.informdb.annotation.AuditTable; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -59,7 +58,6 @@ public class LabSensitivity extends TemporalCore { * * The validFrom {@link TemporalCore#getValidFrom()} is the recording time, or last updated time. */ - @Column(columnDefinition = "timestamp with time zone", nullable = false) + @Column(nullable = false) private Instant observationDatetime; /** diff --git a/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/ids/IdsProgress.java b/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/ids/IdsProgress.java index c87903e3a..fbfbd3c07 100644 --- a/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/ids/IdsProgress.java +++ b/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/ids/IdsProgress.java @@ -2,7 +2,6 @@ import org.springframework.transaction.annotation.Transactional; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @@ -17,9 +16,7 @@ public class IdsProgress { @Id private int id; private int lastProcessedIdsUnid; - @Column(columnDefinition = "timestamp with time zone") private Instant lastProcessedMessageDatetime; - @Column(columnDefinition = "timestamp with time zone") private Instant lastProcessingDatetime; /** From ce33fdd4e3186a25dc5da5ceb564793c6e7ac814 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 11:23:56 +0000 Subject: [PATCH 04/20] Default value FALSE needs to be 0 for the sake of SQL Server --- .../main/java/uk/ac/ucl/rits/inform/informdb/identity/Mrn.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/Mrn.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/Mrn.java index e6aaa9d0a..d85af910c 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/Mrn.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/identity/Mrn.java @@ -67,7 +67,8 @@ public class Mrn implements Serializable { */ private String nhsNumber; - @ColumnDefault("false") + // SQL Server requires 0, not false + @ColumnDefault("0") private boolean researchOptOut; /** From 8c281c2c35da362cb4ef2f1fe6df289eba66d744 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 11:24:15 +0000 Subject: [PATCH 05/20] Remove explicit bytea type as it's the default for Postgres and breaks SQL Server, but for H2 we need to make sure the column length is also specified in audit fields. --- .../informdb/annotation/AuditTableProcessor.java | 10 ++++++++-- .../uk/ac/ucl/rits/inform/informdb/labs/LabResult.java | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java b/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java index cbd38bf37..7c730589b 100644 --- a/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java +++ b/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java @@ -421,11 +421,17 @@ private List generateFields(PrintWriter out, String primaryKey, List // If it's a normal column, then get the @Column properties Column col = field.getAnnotation(Column.class); if (col != null) { + // Because all these values have defaults, we will generate code + // that explicitly specifies the values even if they're not present in the source. + // Confusingly, 255 is always the default length even when type = "text", + // but it's ignored for that type (at least in postgres). boolean nullable = col.nullable(); String columnDefinition = col.columnDefinition(); String name = col.name(); - annotation = String.format("\t@Column(columnDefinition = \"%s\", nullable=%s, name=\"%s\")", - columnDefinition, nullable ? "true" : "false", name); + int length = col.length(); + annotation = String.format( + "\t@Column(columnDefinition = \"%s\", nullable=%s, name=\"%s\", length=%d)", + columnDefinition, nullable ? "true" : "false", name, length); } } else if (!isTemporal) { // If it's a non-temporal FK then preserve the foreign key diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java index 8ce531d44..62cc53163 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java @@ -91,8 +91,9 @@ public class LabResult extends TemporalCore { /** * \brief Value as bytes. + * Array length is maximum allowed by all of H2, Postgres, and SQL Server. */ - @Column(columnDefinition = "bytea") //TODO should this be bytes not bytea + @Column(length = 1000000000) private byte[] valueAsBytes; /** From 4884ca38ab4c7cf61aa688ab414006209743ef7b Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 12:19:09 +0000 Subject: [PATCH 06/20] Remove type which is incompatible with SQL Server --- .../ac/ucl/rits/inform/informdb/visit_recordings/Waveform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/visit_recordings/Waveform.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/visit_recordings/Waveform.java index 128457c0f..8b5b41c14 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/visit_recordings/Waveform.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/visit_recordings/Waveform.java @@ -107,7 +107,7 @@ public class Waveform extends TemporalCore { * \brief Value as a floating point array. */ @Type(type = "uk.ac.ucl.rits.inform.informdb.visit_recordings.WaveformArray") - @Column(columnDefinition = "DOUBLE PRECISION ARRAY", nullable = false) + @Column(nullable = false) private Double[] valuesArray; /* unit goes in visit observation type (or equivalent table...) */ From 4fba02bcb2b6488151f6147dbb29b97f10309123 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 6 Mar 2025 16:01:18 +0000 Subject: [PATCH 07/20] Add and use our custom dialects --- .../resources/application-test.properties | 4 +-- emap-setup/global-configuration-EXAMPLE.yaml | 2 +- .../rits/inform/informdb/H2EmapDialect.java | 19 ++++++++++++++ .../informdb/PostgreSQLEmapDialect.java | 25 +++++++++++++++++++ .../informdb/SQLServer2016EmapDialect.java | 22 ++++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/H2EmapDialect.java create mode 100644 emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java create mode 100644 emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java diff --git a/core/src/test/resources/application-test.properties b/core/src/test/resources/application-test.properties index b672fc92f..9e3f15057 100644 --- a/core/src/test/resources/application-test.properties +++ b/core/src/test/resources/application-test.properties @@ -2,9 +2,9 @@ spring.datasource.url=jdbc:h2:mem:informdb spring.datasource.username= spring.datasource.password= -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.H2Dialect +spring.jpa.properties.hibernate.dialect = uk.ac.ucl.rits.inform.informdb.H2EmapDialect spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.jpa.database-platform=uk.ac.ucl.rits.inform.informdb.H2EmapDialect #spring.jpa.show-sql=true diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index b9b01218a..5a3208c5c 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -82,7 +82,7 @@ dates: # Configurations for the UDS. uds: UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds - UDS_HIBERNATE_DIALECT: org.hibernate.dialect.PostgreSQL95Dialect + UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect UDS_SCHEMA: schemaname UDS_USERNAME: schemauser UDS_PASSWORD: schemapw diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/H2EmapDialect.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/H2EmapDialect.java new file mode 100644 index 000000000..4d08c0c77 --- /dev/null +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/H2EmapDialect.java @@ -0,0 +1,19 @@ +package uk.ac.ucl.rits.inform.informdb; + +import org.hibernate.dialect.H2Dialect; + +import java.sql.Types; + +/** + * Associate JDBC types with H2 types. + */ +public class H2EmapDialect extends H2Dialect { + /** + * H2 seems to accept these Postgres-style types. + */ + public H2EmapDialect() { + super(); + registerColumnType(Types.TIMESTAMP, "timestamp with time zone"); + registerColumnType(Types.ARRAY, "DOUBLE PRECISION ARRAY"); + } +} diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java new file mode 100644 index 000000000..e6c56c63c --- /dev/null +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java @@ -0,0 +1,25 @@ +package uk.ac.ucl.rits.inform.informdb; + +import org.hibernate.dialect.PostgreSQL95Dialect; + +import java.sql.Types; + +/** + * Associate JDBC types with Postgres types. + */ +public class PostgreSQLEmapDialect extends PostgreSQL95Dialect { + /** + * Map all timestamps to "timestamp with time zone" in Postgres, rather + * than specify it in the @Column annotation, which would make it incompatible + * with SQL Server. + * Map all ARRAY types to DOUBLE PRECISION ARRAY. This would be a problem if we + * ever needed to use more than one type of SQL array. Hopefully we will have + * found a better way of storing waveform data before then! + */ + public PostgreSQLEmapDialect() { + super(); + registerColumnType(Types.TIMESTAMP, "timestamp with time zone"); + registerColumnType(Types.ARRAY, "DOUBLE PRECISION ARRAY"); + } + +} diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java new file mode 100644 index 000000000..297e04fab --- /dev/null +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java @@ -0,0 +1,22 @@ +package uk.ac.ucl.rits.inform.informdb; + +import org.hibernate.dialect.SQLServer2016Dialect; + +import java.sql.Types; + +/** + * Associate JDBC types with SQL Server types. + */ +public class SQLServer2016EmapDialect extends SQLServer2016Dialect { + /** + * Map all ARRAY types to varbinary. + * + * This currently doesn't work with waveform data (I think the only place we use arrays), + * but since the main purpose of the SQL Server version is not about waveform data, I think + * we can live with this. Importantly though, it does allow the DDL to be created! + */ + public SQLServer2016EmapDialect() { + super(); + registerColumnType(Types.ARRAY, "varbinary(max)"); + } +} From de9ca637f056abaf2efff3f4c6aeef6bdcabea81 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Fri, 7 Mar 2025 18:06:37 +0000 Subject: [PATCH 08/20] Change dialect in other containers that use the UDS --- hl7-reader/src/main/resources/application.properties | 4 ++-- waveform-reader/src/main/resources/application.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hl7-reader/src/main/resources/application.properties b/hl7-reader/src/main/resources/application.properties index 019469560..eda6ace45 100644 --- a/hl7-reader/src/main/resources/application.properties +++ b/hl7-reader/src/main/resources/application.properties @@ -2,10 +2,10 @@ spring.datasource.url=${UDS_JDBC_URL} spring.datasource.username=${UDS_USERNAME} spring.datasource.password=${UDS_PASSWORD} -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.dialect = uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect spring.jpa.properties.hibernate.default_schema=${UDS_SCHEMA} spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect +spring.jpa.database-platform=uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect spring.jpa.hibernate.ddl-auto = update diff --git a/waveform-reader/src/main/resources/application.properties b/waveform-reader/src/main/resources/application.properties index 9fb93ce3a..a1abf25d8 100644 --- a/waveform-reader/src/main/resources/application.properties +++ b/waveform-reader/src/main/resources/application.properties @@ -3,10 +3,10 @@ spring.datasource.username=${UDS_USERNAME} spring.datasource.password=${UDS_PASSWORD} spring.datasource.hikari.maximum-pool-size=2 -spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect +spring.jpa.properties.hibernate.dialect = uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect spring.jpa.properties.hibernate.default_schema=${UDS_SCHEMA} spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect +spring.jpa.database-platform=uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect spring.jpa.hibernate.ddl-auto = update From 8efe871cb4c25a92c2910e182ce45fb74691c036 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Fri, 7 Mar 2025 18:42:23 +0000 Subject: [PATCH 09/20] Instants must not specify manual type, for SQL Server compatibility --- .../ucl/rits/inform/informdb/TestInstantTypes.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/emap-star/emap-star/src/test/java/uk/ac/ucl/rits/inform/informdb/TestInstantTypes.java b/emap-star/emap-star/src/test/java/uk/ac/ucl/rits/inform/informdb/TestInstantTypes.java index 2ae1febd6..9d5bd2d9d 100644 --- a/emap-star/emap-star/src/test/java/uk/ac/ucl/rits/inform/informdb/TestInstantTypes.java +++ b/emap-star/emap-star/src/test/java/uk/ac/ucl/rits/inform/informdb/TestInstantTypes.java @@ -11,19 +11,23 @@ import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Ensure Instant types are annotated correctly. */ class TestInstantTypes { - private void fieldIsTimestampWithTimeZone(Field field) { + private void fieldHasNoManualType(Field field) { List columnDefinition = Arrays.stream(field.getAnnotationsByType(Column.class)) .map(Column::columnDefinition) .collect(Collectors.toList()); - assertEquals(1, columnDefinition.size(), - String.format("field '%s' needs exactly one @Column annotation with a columnDefinition specified", field.getName())); - assertEquals("timestamp with time zone", columnDefinition.get(0)); + if (columnDefinition.size() == 1) { + // columnDefinition can be either absent or empty string + assertEquals("", columnDefinition.get(0), + String.format("Instant field '%s' cannot specify non-empty columnDefinition text", + field.getName())); + } } /** @@ -35,6 +39,6 @@ void testEntityInstantFields(Class entityClass) { Arrays.stream(entityClass.getDeclaredFields()) .filter(field -> field.getType().equals(Instant.class)) - .forEach(this::fieldIsTimestampWithTimeZone); + .forEach(this::fieldHasNoManualType); } } From 666e0e2b65209e831ed532914f810dbd0f9dacf9 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Wed, 19 Mar 2025 10:42:43 +0000 Subject: [PATCH 10/20] SQL Server port needs to specified in global envs --- global-config-envs.EXAMPLE | 1 + 1 file changed, 1 insertion(+) diff --git a/global-config-envs.EXAMPLE b/global-config-envs.EXAMPLE index ece509d24..e0dcc211f 100644 --- a/global-config-envs.EXAMPLE +++ b/global-config-envs.EXAMPLE @@ -3,5 +3,6 @@ RABBITMQ_PORT=5672 RABBITMQ_ADMIN_PORT=5674 GLOWROOT_ADMIN_PORT=4000 FAKEUDS_PORT=5433 +FAKEUDS_MSSQL_PORT=1433 HL7_READER_PORT=9999 PORTAL_PORT= From 35d5263e19feb684a708da7f37dce024a73b993e Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Wed, 19 Mar 2025 17:16:41 +0000 Subject: [PATCH 11/20] Fix (most) emap-setup tests --- .../tests/data/test-global-configuration-only-docs.yaml | 4 +++- .../tests/data/test-global-configuration-onlyhl7.yaml | 3 +++ emap-setup/tests/data/test-global-configuration.yaml | 5 ++++- emap-setup/tests/test_runner.py | 6 +++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/emap-setup/tests/data/test-global-configuration-only-docs.yaml b/emap-setup/tests/data/test-global-configuration-only-docs.yaml index 1b5f97fc7..edf429bdd 100644 --- a/emap-setup/tests/data/test-global-configuration-only-docs.yaml +++ b/emap-setup/tests/data/test-global-configuration-only-docs.yaml @@ -6,11 +6,13 @@ EMAP_PROJECT_NAME: only_emap_setup repositories: - emap_documentation: + internal_emap_documentation: branch: main # For testing outside the GAE, you can enable a fake UDS fake_uds: enable_fake_uds: false +fake_mssql: + enable_fake_mssql: false # config related to waveform data ingress waveform: enable_waveform: false diff --git a/emap-setup/tests/data/test-global-configuration-onlyhl7.yaml b/emap-setup/tests/data/test-global-configuration-onlyhl7.yaml index c8c15a29b..094c704f2 100644 --- a/emap-setup/tests/data/test-global-configuration-onlyhl7.yaml +++ b/emap-setup/tests/data/test-global-configuration-onlyhl7.yaml @@ -43,6 +43,9 @@ core: fake_uds: enable_fake_uds: false +fake_mssql: + enable_fake_mssql: false + # config related to waveform data ingress waveform: enable_waveform: false diff --git a/emap-setup/tests/data/test-global-configuration.yaml b/emap-setup/tests/data/test-global-configuration.yaml index ca398ce42..ad430093f 100644 --- a/emap-setup/tests/data/test-global-configuration.yaml +++ b/emap-setup/tests/data/test-global-configuration.yaml @@ -7,7 +7,7 @@ EMAP_PROJECT_NAME: my_project_name repositories: - InformDB: + emap: branch: develop hl7-vitals: branch: main @@ -64,6 +64,9 @@ informdb: fake_uds: enable_fake_uds: false +fake_mssql: + enable_fake_mssql: false + # config related to waveform data ingress waveform: enable_waveform: false diff --git a/emap-setup/tests/test_runner.py b/emap-setup/tests/test_runner.py index 94ce9cf9d..f548b4011 100644 --- a/emap-setup/tests/test_runner.py +++ b/emap-setup/tests/test_runner.py @@ -36,14 +36,14 @@ def test_clone_then_clean_repos(): runner.run() # Ensure that the cloned directory exists - assert exists("emap_documentation") + assert exists("internal_emap_documentation") assert exists("config") # and can be cleaned runner = EMAPRunner(args=parser.parse_args(["setup", "-c"]), config=config) runner.run() - assert not exists("emap_documentation") + assert not exists("internal_emap_documentation") @work_in_tmp_directory(to_copy=None) @@ -58,7 +58,7 @@ def test_double_clone(): runner = EMAPRunner(args=parser.parse_args(args), config=config) runner.run() # Make some un-pushed changes to newly cloned repo - file_to_keep = Path('emap_documentation/my_favourite_file.txt') + file_to_keep = Path('internal_emap_documentation/my_favourite_file.txt') with open(file_to_keep, 'w') as fh: fh.write("cheese") From 7b800a23b177a376373ef62456ccb480fb58e932 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Wed, 19 Mar 2025 17:17:00 +0000 Subject: [PATCH 12/20] Add build args to the environment along with the global envs --- .../emap_runner/docker/docker_runner.py | 20 ++++++++++++++----- emap-setup/emap_runner/setup/repos.py | 2 +- emap-setup/global-configuration-EXAMPLE.yaml | 4 ++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/emap-setup/emap_runner/docker/docker_runner.py b/emap-setup/emap_runner/docker/docker_runner.py index 58aba635d..be094dd15 100644 --- a/emap-setup/emap_runner/docker/docker_runner.py +++ b/emap-setup/emap_runner/docker/docker_runner.py @@ -175,7 +175,7 @@ def _check_paths_exist(self) -> None: @staticmethod def _all_global_environment_variables() -> dict: """Dictionary of all global variables present in - config/global-config-envs added to the currently set env vars""" + config/global-config-envs or config/*-build-args added to the currently set env vars""" config_dir_path = Path(Path.cwd(), "config") @@ -187,10 +187,20 @@ def _all_global_environment_variables() -> dict: env_vars = os.environ.copy() for item in config_dir_path.iterdir(): - # only necessary to read the global config variables; rest will be - # pulled through containers directly - if item.is_file() and item.stem == "global-config-envs": - env_vars.update(EnvironmentFile(item).environment_variables) + item: Path + # only necessary to read the global config variables and variables that become build args; + # rest will be pulled through containers directly + if item.is_file() and (item.stem == "global-config-envs" or item.stem.endswith('-build-args')): + new_variables = EnvironmentFile(item).environment_variables + # Can't see an easy way of keeping the build args separate per image, so just put them all + # in the environment and warn here if any variables conflict. + for nv in new_variables.keys(): + if nv in env_vars: + logger.warning( + "Conflicting build time variables:\n%s=%s [from %s] overwriting:\n%s=%s", + nv, new_variables[nv], item.stem, nv, env_vars[nv] + ) + env_vars.update(new_variables) return env_vars diff --git a/emap-setup/emap_runner/setup/repos.py b/emap-setup/emap_runner/setup/repos.py index ddb9879ba..935e06fb2 100644 --- a/emap-setup/emap_runner/setup/repos.py +++ b/emap-setup/emap_runner/setup/repos.py @@ -155,7 +155,7 @@ def environment_files(self) -> List[EnvironmentFile]: @staticmethod def _add_env_to_files(path: Path, files: List[EnvironmentFile]): - if path.is_file() and str(path).endswith("-envs.EXAMPLE"): + if path.is_file() and str(path).endswith(("-envs.EXAMPLE", "-build-args.EXAMPLE")): files.append(EnvironmentFile.from_example_file(path)) @staticmethod diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index 5a3208c5c..702155e39 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -82,7 +82,11 @@ dates: # Configurations for the UDS. uds: UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds + # dialect to use for core informdb tables UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect + # profile name to use for liquibase or other places where there is an opportunity to compute the correct value + # possible values: sqlserver, postgres + UDS_HIBERNATE_DIALECT_PROFILE: postgres UDS_SCHEMA: schemaname UDS_USERNAME: schemauser UDS_PASSWORD: schemapw From 0a3eee45a43dd7b3fd770d1febb8a9cc0665d2aa Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Fri, 21 Mar 2025 16:12:00 +0000 Subject: [PATCH 13/20] hl7-reader needs to write to UDS too, so needs sql-server --- hl7-reader/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hl7-reader/pom.xml b/hl7-reader/pom.xml index 1d362c486..8375cd8ae 100644 --- a/hl7-reader/pom.xml +++ b/hl7-reader/pom.xml @@ -104,6 +104,11 @@ commons-lang3 + + com.microsoft.sqlserver + mssql-jdbc + + org.postgresql postgresql From e34c27e63d96d94d6fb4c3afd458d6562e19b49b Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Tue, 25 Mar 2025 10:53:01 +0000 Subject: [PATCH 14/20] Temporary workaround for missing Emap dialects in hl7-reader --- emap-setup/global-configuration-EXAMPLE.yaml | 2 ++ hl7-reader/hl7-reader-config-envs.EXAMPLE | 1 + hl7-reader/src/main/resources/application.properties | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index 702155e39..fef4f2f5e 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -84,6 +84,8 @@ uds: UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds # dialect to use for core informdb tables UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect + # dialect for modules that don't have access to emap-star (which contains the above code) + UDS_HIBERNATE_DIALECT_2: org.hibernate.dialect.PostgreSQL95Dialect # profile name to use for liquibase or other places where there is an opportunity to compute the correct value # possible values: sqlserver, postgres UDS_HIBERNATE_DIALECT_PROFILE: postgres diff --git a/hl7-reader/hl7-reader-config-envs.EXAMPLE b/hl7-reader/hl7-reader-config-envs.EXAMPLE index 8bb2599ff..bbaac0106 100644 --- a/hl7-reader/hl7-reader-config-envs.EXAMPLE +++ b/hl7-reader/hl7-reader-config-envs.EXAMPLE @@ -10,6 +10,7 @@ UDS_JDBC_URL=jdbc:postgresql://host.docker.internal:5432/uds UDS_SCHEMA=public UDS_USERNAME=postgres UDS_PASSWORD=postgres +UDS_HIBERNATE_DIALECT_2= SPRING_RABBITMQ_HOST=rabbitmq SPRING_RABBITMQ_PORT=5672 SPRING_RABBITMQ_USERNAME=emap diff --git a/hl7-reader/src/main/resources/application.properties b/hl7-reader/src/main/resources/application.properties index eda6ace45..a6acce24d 100644 --- a/hl7-reader/src/main/resources/application.properties +++ b/hl7-reader/src/main/resources/application.properties @@ -2,10 +2,10 @@ spring.datasource.url=${UDS_JDBC_URL} spring.datasource.username=${UDS_USERNAME} spring.datasource.password=${UDS_PASSWORD} -spring.jpa.properties.hibernate.dialect = uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect +spring.jpa.properties.hibernate.dialect = ${UDS_HIBERNATE_DIALECT_2} spring.jpa.properties.hibernate.default_schema=${UDS_SCHEMA} spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect +spring.jpa.database-platform=${UDS_HIBERNATE_DIALECT_2} spring.jpa.hibernate.ddl-auto = update From 90014910e8a1d93d988071ae638d364ce19fa8be Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Wed, 26 Mar 2025 14:39:27 +0000 Subject: [PATCH 15/20] Use SQL Server 2019 for fake UDS because 2022 locks up on every query on the GAE. --- core/docker-compose.fakeuds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/docker-compose.fakeuds.yml b/core/docker-compose.fakeuds.yml index 9d28e787f..1c3a0c1e2 100644 --- a/core/docker-compose.fakeuds.yml +++ b/core/docker-compose.fakeuds.yml @@ -15,7 +15,7 @@ services: profiles: - fakeuds-pg fakeuds-mssql: - image: mcr.microsoft.com/mssql/server:2022-CU17-ubuntu-22.04 + image: mcr.microsoft.com/mssql/server:2019-CU32-ubuntu-20.04 env_file: - ../../config/fakeuds-mssql-config-envs environment: From 631a2b64aaca29c75dcc595040f79af297b1ee6c Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Fri, 28 Mar 2025 17:49:01 +0000 Subject: [PATCH 16/20] Instead of specifying SQL type "text", which has the wrong meaning on SQL Server, use @Lob annotation which maps to "text" and "varchar(max)" as appropriate. --- .../inform/datasinks/emapstar/repos/IdsEffectLogging.java | 6 +++--- .../ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java | 2 ++ .../ucl/rits/inform/informdb/SQLServer2016EmapDialect.java | 1 + .../rits/inform/informdb/conditions/PatientCondition.java | 4 ++-- .../rits/inform/informdb/consults/ConsultationRequest.java | 3 ++- .../uk/ac/ucl/rits/inform/informdb/forms/FormAnswer.java | 3 ++- .../ac/ucl/rits/inform/informdb/forms/FormDefinition.java | 3 ++- .../java/uk/ac/ucl/rits/inform/informdb/labs/LabOrder.java | 4 ++-- .../uk/ac/ucl/rits/inform/informdb/labs/LabResult.java | 5 +++-- .../uk/ac/ucl/rits/inform/informdb/labs/LabSample.java | 4 ++-- .../uk/ac/ucl/rits/inform/informdb/questions/Question.java | 4 +++- .../ucl/rits/inform/informdb/questions/RequestAnswer.java | 3 ++- .../inform/informdb/visit_recordings/VisitObservation.java | 5 +++-- .../ucl/rits/inform/datasources/idstables/IdsMaster.java | 7 +++---- 14 files changed, 32 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/uk/ac/ucl/rits/inform/datasinks/emapstar/repos/IdsEffectLogging.java b/core/src/main/java/uk/ac/ucl/rits/inform/datasinks/emapstar/repos/IdsEffectLogging.java index 9fabdc67c..a635e7329 100644 --- a/core/src/main/java/uk/ac/ucl/rits/inform/datasinks/emapstar/repos/IdsEffectLogging.java +++ b/core/src/main/java/uk/ac/ucl/rits/inform/datasinks/emapstar/repos/IdsEffectLogging.java @@ -1,11 +1,11 @@ package uk.ac.ucl.rits.inform.datasinks.emapstar.repos; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; +import javax.persistence.Lob; import javax.persistence.Table; import java.io.PrintWriter; import java.io.StringWriter; @@ -35,9 +35,9 @@ public class IdsEffectLogging { private Long processMessageDuration; private Boolean error; private String messageType; - @Column(columnDefinition = "text") + @Lob private String message; - @Column(columnDefinition = "text") + @Lob private String stackTrace; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java index e6c56c63c..8a6c88b5f 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/PostgreSQLEmapDialect.java @@ -20,6 +20,8 @@ public PostgreSQLEmapDialect() { super(); registerColumnType(Types.TIMESTAMP, "timestamp with time zone"); registerColumnType(Types.ARRAY, "DOUBLE PRECISION ARRAY"); + // Map @Lob to "text" + registerColumnType(Types.CLOB, "text"); } } diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java index 297e04fab..6fc83e7c2 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/SQLServer2016EmapDialect.java @@ -18,5 +18,6 @@ public class SQLServer2016EmapDialect extends SQLServer2016Dialect { public SQLServer2016EmapDialect() { super(); registerColumnType(Types.ARRAY, "varbinary(max)"); + // it doesn't seem to be necessary to map CLOB to varchar(max) } } diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java index 4b30e6f7e..ec6d270af 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/conditions/PatientCondition.java @@ -9,13 +9,13 @@ import uk.ac.ucl.rits.inform.informdb.identity.HospitalVisit; import uk.ac.ucl.rits.inform.informdb.identity.Mrn; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.Table; import java.time.Instant; @@ -139,7 +139,7 @@ public class PatientCondition extends TemporalCore { * If not of type String, this field will still contain the string representation of the value. * . */ - @Column(columnDefinition = "text") + @Lob private String valueAsText; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormDefinition.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormDefinition.java index d4e821a7e..85ae49596 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormDefinition.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/forms/FormDefinition.java @@ -12,6 +12,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Lob; import java.time.Instant; /** @@ -55,7 +56,7 @@ public class FormDefinition extends TemporalCore { /** * \brief Additional information supplied. */ - @Column(columnDefinition = "text") + @Lob private String clinicalInformation; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java index 62cc53163..cdd18c04b 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabResult.java @@ -13,6 +13,7 @@ import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.Table; import java.time.Instant; @@ -81,7 +82,7 @@ public class LabResult extends TemporalCore { /** * \brief Value as text. */ - @Column(columnDefinition = "text") + @Lob private String valueAsText; /** @@ -127,7 +128,7 @@ public class LabResult extends TemporalCore { /** * \brief Additional comments. */ - @Column(columnDefinition = "text") + @Lob private String comment; public LabResult() {} diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java index 10e675d53..808ed840d 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/labs/LabSample.java @@ -7,13 +7,13 @@ import uk.ac.ucl.rits.inform.informdb.annotation.AuditTable; import uk.ac.ucl.rits.inform.informdb.identity.Mrn; -import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.Table; import java.time.Instant; @@ -87,7 +87,7 @@ public class LabSample extends TemporalCore { * * E.g. Bone marrow trephine biopsy */ - @Column(columnDefinition = "text") + @Lob private String collectionMethod; public LabSample() {} diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/Question.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/Question.java index bb7ef6ee6..c543d0346 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/Question.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/Question.java @@ -9,6 +9,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Lob; import java.time.Instant; /** @@ -38,7 +39,8 @@ public class Question { /** * \brief Text content of the question. */ - @Column(columnDefinition = "text", nullable = false) + @Lob + @Column(nullable = false) private String question; /** diff --git a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/RequestAnswer.java b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/RequestAnswer.java index 2751e609f..c46ca20d1 100644 --- a/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/RequestAnswer.java +++ b/emap-star/emap-star/src/main/java/uk/ac/ucl/rits/inform/informdb/questions/RequestAnswer.java @@ -13,6 +13,7 @@ import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.ManyToOne; import javax.persistence.Table; import java.time.Instant; @@ -46,7 +47,7 @@ public class RequestAnswer extends TemporalCore Date: Fri, 28 Mar 2025 20:46:20 +0000 Subject: [PATCH 17/20] IDS is always Postgres so keep the literal "text" type! --- .../ucl/rits/inform/datasources/idstables/IdsMaster.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/idstables/IdsMaster.java b/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/idstables/IdsMaster.java index 23ba09395..7dc6e49bb 100644 --- a/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/idstables/IdsMaster.java +++ b/hl7-reader/src/main/java/uk/ac/ucl/rits/inform/datasources/idstables/IdsMaster.java @@ -1,10 +1,11 @@ package uk.ac.ucl.rits.inform.datasources.idstables; +import java.time.Instant; + +import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; -import javax.persistence.Lob; import javax.persistence.Table; -import java.time.Instant; /** * Representation of the main IDS table. Usually for reading but we can also @@ -33,7 +34,7 @@ public class IdsMaster { private String messageformat; private String messageversion; private Instant messagedatetime; - @Lob + @Column(columnDefinition = "text") private String hl7message; private Instant persistdatetime; From 2fcea6f36e4b757db2c9dba4399aeb6cc73cefd9 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Mon, 31 Mar 2025 14:39:37 +0100 Subject: [PATCH 18/20] Need to propagate @Lob annotations to the Audit tables too. --- .../annotation/AuditTableProcessor.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java b/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java index 7c730589b..0fc8188f3 100644 --- a/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java +++ b/emap-star/emap-star-annotations/src/main/java/uk/ac/ucl/rits/inform/informdb/annotation/AuditTableProcessor.java @@ -22,6 +22,7 @@ import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; +import javax.persistence.Lob; import javax.persistence.MapsId; import javax.persistence.OneToMany; import javax.persistence.Table; @@ -192,6 +193,7 @@ private void generateImports(PrintWriter out, String baseImport) { out.println("import javax.persistence.Inheritance;"); out.println("import javax.persistence.InheritanceType;"); out.println("import javax.persistence.Index;"); + out.println("import javax.persistence.Lob;"); out.println("import javax.persistence.ManyToOne;"); out.println("import javax.persistence.OneToOne;"); out.println("import javax.persistence.Table;"); @@ -270,7 +272,7 @@ private List generateFields(PrintWriter out, String primaryKey, List List fieldShorts = new ArrayList<>(); // Primary key - this.generateSingleField(out, "\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)", "Long", primaryKey); + this.generateSingleField(out, List.of("\t@Id\n\t@GeneratedValue(strategy = GenerationType.AUTO)"), "Long", primaryKey); // All other fields for (VariableElement field : fields) { @@ -414,7 +416,7 @@ private List generateFields(PrintWriter out, String primaryKey, List } - String annotation = null; + List annotations = new ArrayList<>(); String foreignKeyName = null; if (!isForeignKey) { @@ -429,9 +431,13 @@ private List generateFields(PrintWriter out, String primaryKey, List String columnDefinition = col.columnDefinition(); String name = col.name(); int length = col.length(); - annotation = String.format( + annotations.add(String.format( "\t@Column(columnDefinition = \"%s\", nullable=%s, name=\"%s\", length=%d)", - columnDefinition, nullable ? "true" : "false", name, length); + columnDefinition, nullable ? "true" : "false", name, length)); + } + Lob lob = field.getAnnotation(Lob.class); + if (lob != null) { + annotations.add("\t@Lob"); } } else if (!isTemporal) { // If it's a non-temporal FK then preserve the foreign key @@ -448,7 +454,7 @@ private List generateFields(PrintWriter out, String primaryKey, List annot.append(mirror.toString()); annot.append("\n"); } - annotation = annot.toString().stripTrailing(); + annotations.add(annot.toString().stripTrailing()); } else { // If it's a foreign key that gets turned in to a long because @@ -477,15 +483,15 @@ private List generateFields(PrintWriter out, String primaryKey, List String colDef = joinColumn.columnDefinition(); boolean nullable = joinColumn.nullable(); String name = joinColumn.name(); - annotation = String.format("\t@Column(columnDefinition = \"%s\", nullable=%s, name=\"%s\")", colDef, - nullable ? "true" : "false", name); + annotations.add(String.format("\t@Column(columnDefinition = \"%s\", nullable=%s, name=\"%s\")", colDef, + nullable ? "true" : "false", name)); } } String fieldName = field.getSimpleName().toString(); // Foreign keys are only treated specially if they are temporal! fieldShorts.add(new FieldStore(fieldName, isTemporal && isForeignKey, foreignKeyName)); - this.generateSingleField(out, annotation, typeName, fieldName); + this.generateSingleField(out, annotations, typeName, fieldName); } return fieldShorts; @@ -498,10 +504,12 @@ private List generateFields(PrintWriter out, String primaryKey, List * @param typeName The type of the field. * @param fieldName The name of the field. */ - private void generateSingleField(PrintWriter out, String annotations, String typeName, String fieldName) { + private void generateSingleField(PrintWriter out, List annotations, String typeName, String fieldName) { // Field declaration if (annotations != null) { - out.println(annotations); + for (String annotation : annotations) { + out.println(annotation); + } } out.print("\tprivate "); out.print(typeName); From e38e2e9f32ad7a98b9c17001fc996d426b502326 Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Thu, 3 Apr 2025 17:55:21 +0100 Subject: [PATCH 19/20] Add emap-star to hl7-reader just so we can access the new Hibernate dialects. --- emap-setup/global-configuration-EXAMPLE.yaml | 2 -- hl7-reader/Dockerfile | 4 ++++ hl7-reader/hl7-reader-config-envs.EXAMPLE | 2 +- hl7-reader/pom.xml | 12 ++++++++++++ hl7-reader/src/main/resources/application.properties | 4 ++-- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index fef4f2f5e..702155e39 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -84,8 +84,6 @@ uds: UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds # dialect to use for core informdb tables UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect - # dialect for modules that don't have access to emap-star (which contains the above code) - UDS_HIBERNATE_DIALECT_2: org.hibernate.dialect.PostgreSQL95Dialect # profile name to use for liquibase or other places where there is an opportunity to compute the correct value # possible values: sqlserver, postgres UDS_HIBERNATE_DIALECT_PROFILE: postgres diff --git a/hl7-reader/Dockerfile b/hl7-reader/Dockerfile index b39a29d1e..f73168a6d 100644 --- a/hl7-reader/Dockerfile +++ b/hl7-reader/Dockerfile @@ -21,6 +21,10 @@ RUN source /app/set_mvn_proxy.sh; mvn de.qaware.maven:go-offline-maven-plugin:re # Install emap-interchange COPY emap-interchange/src/ /app/emap-interchange/src/ RUN source /app/set_mvn_proxy.sh; mvn install -f /app/emap-interchange/pom.xml + +COPY emap-star/ /app/emap-star/ +RUN source /app/set_mvn_proxy.sh; mvn install -Dmaven.test.skip=true -f /app/emap-star/pom.xml + # Install hl7-reader WORKDIR /app/hl7-reader COPY hl7-reader/src/ /app/hl7-reader/src/ diff --git a/hl7-reader/hl7-reader-config-envs.EXAMPLE b/hl7-reader/hl7-reader-config-envs.EXAMPLE index bbaac0106..ad3019096 100644 --- a/hl7-reader/hl7-reader-config-envs.EXAMPLE +++ b/hl7-reader/hl7-reader-config-envs.EXAMPLE @@ -10,7 +10,7 @@ UDS_JDBC_URL=jdbc:postgresql://host.docker.internal:5432/uds UDS_SCHEMA=public UDS_USERNAME=postgres UDS_PASSWORD=postgres -UDS_HIBERNATE_DIALECT_2= +UDS_HIBERNATE_DIALECT= SPRING_RABBITMQ_HOST=rabbitmq SPRING_RABBITMQ_PORT=5672 SPRING_RABBITMQ_USERNAME=emap diff --git a/hl7-reader/pom.xml b/hl7-reader/pom.xml index 8375cd8ae..35d60dea3 100644 --- a/hl7-reader/pom.xml +++ b/hl7-reader/pom.xml @@ -22,6 +22,7 @@ 10.3.1 3.3.0 2.3 + 2.7 2.7 1.2.8 @@ -36,6 +37,11 @@ + + uk.ac.ucl.rits.inform + emap-star + ${emap-star.version} + uk.ac.ucl.rits.inform emap-interchange @@ -205,6 +211,12 @@ ${go-offline-maven-plugin.version} + + uk.ac.ucl.rits.inform + emap-star + ${emap-star.version} + MAIN + uk.ac.ucl.rits.inform emap-interchange diff --git a/hl7-reader/src/main/resources/application.properties b/hl7-reader/src/main/resources/application.properties index a6acce24d..987ec2f07 100644 --- a/hl7-reader/src/main/resources/application.properties +++ b/hl7-reader/src/main/resources/application.properties @@ -2,10 +2,10 @@ spring.datasource.url=${UDS_JDBC_URL} spring.datasource.username=${UDS_USERNAME} spring.datasource.password=${UDS_PASSWORD} -spring.jpa.properties.hibernate.dialect = ${UDS_HIBERNATE_DIALECT_2} +spring.jpa.properties.hibernate.dialect = ${UDS_HIBERNATE_DIALECT} spring.jpa.properties.hibernate.default_schema=${UDS_SCHEMA} spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false -spring.jpa.database-platform=${UDS_HIBERNATE_DIALECT_2} +spring.jpa.database-platform=${UDS_HIBERNATE_DIALECT} spring.jpa.hibernate.ddl-auto = update From b1d8ae9c3fe466bb2795684fc30c8a38162141ea Mon Sep 17 00:00:00 2001 From: Jeremy Stein Date: Fri, 4 Apr 2025 16:04:49 +0100 Subject: [PATCH 20/20] Include example configs for both Postgres and SQL Server, and make it easy to switch between them. --- emap-setup/global-configuration-EXAMPLE.yaml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/emap-setup/global-configuration-EXAMPLE.yaml b/emap-setup/global-configuration-EXAMPLE.yaml index 702155e39..0e5e51ba7 100644 --- a/emap-setup/global-configuration-EXAMPLE.yaml +++ b/emap-setup/global-configuration-EXAMPLE.yaml @@ -80,7 +80,8 @@ dates: end: # Configurations for the UDS. -uds: +# For postgres +postgres-uds: &postgres-uds UDS_JDBC_URL: jdbc:postgresql://uds_db:5432/uds # dialect to use for core informdb tables UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.PostgreSQLEmapDialect @@ -91,6 +92,21 @@ uds: UDS_USERNAME: schemauser UDS_PASSWORD: schemapw +# For SQL Server +sqlserver-uds: &sqlserver-uds + UDS_JDBC_URL: jdbc:sqlserver://fakeuds-mssql:1433;Encrypt=false;TrustServerCertificate=true + # dialect to use for core informdb tables + UDS_HIBERNATE_DIALECT: uk.ac.ucl.rits.inform.informdb.SQLServer2016EmapDialect + # profile name to use for liquibase or other places where there is an opportunity to compute the correct value + UDS_HIBERNATE_DIALECT_PROFILE: sqlserver + UDS_SCHEMA: dbo + UDS_USERNAME: sa + UDS_PASSWORD: EXAMPLE_VALUE + + +# Switch the actual config between Postgres and SQL Server here +uds: *postgres-uds + # These are the configurations for glowroot (a Java application performance # management system). glowroot: