Skip to content

Commit

Permalink
SW-6282 Added isAdHoc flag and ObservationType to observation and mon…
Browse files Browse the repository at this point in the history
…itoring plot tables (#2681)
  • Loading branch information
tommylau523 authored Dec 11, 2024
1 parent 423929c commit 88ebbcd
Show file tree
Hide file tree
Showing 24 changed files with 119 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ val ENUM_TABLES =
isLocalizable = false),
EnumTable(
"observation_states", listOf("observations\\.state_id"), isLocalizable = false),
EnumTable("observation_types", listOf("observations\\.observation_type_id")),
EnumTable("planting_types"),
EnumTable(
"recorded_plant_statuses",
Expand Down Expand Up @@ -317,6 +318,9 @@ val ID_WRAPPERS =
listOf("monitoring_plot_histories\\.id", ".*\\.monitoring_plot_history_id")),
IdWrapper("MonitoringPlotId", listOf("monitoring_plots\\.id", ".*\\..*_plot_id")),
IdWrapper("ObservationId", listOf("observations\\.id", ".*\\.observation_id")),
IdWrapper(
"ObservationTypeId",
listOf("observation_types\\.id", ".*\\.observation_type_id")),
IdWrapper("ObservedPlotCoordinatesId", listOf("observed_plot_coordinates\\.id")),
IdWrapper("PlantingId", listOf("plantings\\.id")),
IdWrapper("PlantingSeasonId", listOf("planting_seasons\\.id")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.terraformation.backend.db.default_schema.tables.daos.OrganizationsDao
import com.terraformation.backend.db.tracking.MonitoringPlotId
import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.PlantingSeasonId
import com.terraformation.backend.db.tracking.PlantingSiteId
import com.terraformation.backend.db.tracking.PlantingSubzoneId
Expand Down Expand Up @@ -699,6 +700,8 @@ class AdminPlantingSitesController(
NewObservationModel(
endDate = LocalDate.parse(endDate),
id = null,
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = plantingSiteId,
requestedSubzoneIds = requestedSubzoneIds ?: emptySet(),
startDate = LocalDate.parse(startDate),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class MonitoringPlotsTable(tables: SearchTables) : SearchTable() {
timestampField("createdTime", MONITORING_PLOTS.CREATED_TIME),
textField("fullName", MONITORING_PLOTS.FULL_NAME),
idWrapperField("id", MONITORING_PLOTS.ID) { MonitoringPlotId(it) },
booleanField("isAdHoc", MONITORING_PLOTS.IS_AD_HOC),
booleanField("isAvailable", MONITORING_PLOTS.IS_AVAILABLE),
timestampField("modifiedTime", MONITORING_PLOTS.MODIFIED_TIME),
textField("name", MONITORING_PLOTS.NAME),
coordinateField("northeastLatitude", MONITORING_PLOTS.BOUNDARY, NORTHEAST, LATITUDE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ class ObservationsTable(private val tables: SearchTables) : SearchTable() {
timestampField("createdTime", OBSERVATIONS.CREATED_TIME),
dateField("endDate", OBSERVATIONS.END_DATE),
idWrapperField("id", OBSERVATIONS.ID) { ObservationId(it) },
booleanField("isAdHoc", OBSERVATIONS.IS_AD_HOC),
idWrapperField("plantingSiteHistoryId", OBSERVATIONS.PLANTING_SITE_HISTORY_ID) {
PlantingSiteHistoryId(it)
},
dateField("startDate", OBSERVATIONS.START_DATE),
enumField("type", OBSERVATIONS.OBSERVATION_TYPE_ID),
)

override val inheritsVisibilityFrom: SearchTable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationPlotPosition
import com.terraformation.backend.db.tracking.ObservationPlotStatus
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.PlantingSiteHistoryId
import com.terraformation.backend.db.tracking.PlantingSiteId
import com.terraformation.backend.db.tracking.PlantingSubzoneId
Expand Down Expand Up @@ -1012,6 +1013,8 @@ data class ScheduleObservationRequestPayload(
NewObservationModel(
endDate = endDate,
id = null,
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = plantingSiteId,
requestedSubzoneIds = requestedSubzoneIds ?: emptySet(),
startDate = startDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ class ObservationStore(
ObservationsRow(
createdTime = clock.instant(),
endDate = newModel.endDate,
isAdHoc = newModel.isAdHoc,
observationTypeId = newModel.observationType,
plantingSiteId = newModel.plantingSiteId,
startDate = newModel.startDate,
stateId = ObservationState.Upcoming,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1576,6 +1576,7 @@ class PlantingSiteStore(
createdBy = userId,
createdTime = now,
fullName = "${subzone.fullName}-$plotNumber",
isAdHoc = false,
modifiedBy = userId,
modifiedTime = now,
name = "$plotNumber",
Expand Down Expand Up @@ -1627,6 +1628,7 @@ class PlantingSiteStore(
createdBy = userId,
createdTime = now,
fullName = "${subzone.fullName}-$plotNumber",
isAdHoc = false,
modifiedBy = userId,
modifiedTime = now,
name = "$plotNumber",
Expand Down Expand Up @@ -1703,6 +1705,7 @@ class PlantingSiteStore(
DSL.select(
MONITORING_PLOTS.ID,
MONITORING_PLOTS.FULL_NAME,
MONITORING_PLOTS.IS_AD_HOC,
MONITORING_PLOTS.IS_AVAILABLE,
MONITORING_PLOTS.NAME,
MONITORING_PLOTS.PERMANENT_CLUSTER,
Expand All @@ -1717,6 +1720,7 @@ class PlantingSiteStore(
MonitoringPlotModel(
boundary = record[monitoringPlotBoundaryField]!! as Polygon,
id = record[MONITORING_PLOTS.ID]!!,
isAdHoc = record[MONITORING_PLOTS.IS_AD_HOC]!!,
isAvailable = record[MONITORING_PLOTS.IS_AVAILABLE]!!,
fullName = record[MONITORING_PLOTS.FULL_NAME]!!,
name = record[MONITORING_PLOTS.NAME]!!,
Expand Down Expand Up @@ -1765,7 +1769,11 @@ class PlantingSiteStore(
): Field<List<ExistingPlantingSubzoneModel>> {
val plotsField =
if (depth == PlantingSiteDepth.Plot)
monitoringPlotsMultiset(PLANTING_SUBZONES.ID.eq(MONITORING_PLOTS.PLANTING_SUBZONE_ID))
monitoringPlotsMultiset(
DSL.and(
PLANTING_SUBZONES.ID.eq(MONITORING_PLOTS.PLANTING_SUBZONE_ID),
MONITORING_PLOTS.IS_AD_HOC.isFalse(),
))
else null

return DSL.multiset(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.locationtech.jts.geom.Polygon
data class MonitoringPlotModel(
val boundary: Polygon,
val id: MonitoringPlotId,
val isAdHoc: Boolean,
val isAvailable: Boolean,
val fullName: String,
val name: String,
Expand All @@ -20,6 +21,7 @@ data class MonitoringPlotModel(
fun equals(other: Any?, tolerance: Double): Boolean {
return other is MonitoringPlotModel &&
id == other.id &&
isAdHoc == other.isAdHoc &&
isAvailable == other.isAvailable &&
fullName == other.fullName &&
name == other.name &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.terraformation.backend.tracking.model

import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.PlantingSiteHistoryId
import com.terraformation.backend.db.tracking.PlantingSiteId
import com.terraformation.backend.db.tracking.PlantingSubzoneId
Expand All @@ -15,6 +16,8 @@ data class ObservationModel<ID : ObservationId?>(
val completedTime: Instant? = null,
val endDate: LocalDate,
val id: ID,
val isAdHoc: Boolean,
val observationType: ObservationType,
val plantingSiteHistoryId: PlantingSiteHistoryId? = null,
val plantingSiteId: PlantingSiteId,
val requestedSubzoneIds: Set<PlantingSubzoneId> = emptySet(),
Expand Down Expand Up @@ -48,6 +51,8 @@ data class ObservationModel<ID : ObservationId?>(
completedTime = record[OBSERVATIONS.COMPLETED_TIME],
endDate = record[OBSERVATIONS.END_DATE]!!,
id = record[OBSERVATIONS.ID]!!,
isAdHoc = record[OBSERVATIONS.IS_AD_HOC]!!,
observationType = record[OBSERVATIONS.OBSERVATION_TYPE_ID]!!,
plantingSiteHistoryId = record[OBSERVATIONS.PLANTING_SITE_HISTORY_ID],
plantingSiteId = record[OBSERVATIONS.PLANTING_SITE_ID]!!,
requestedSubzoneIds = record[requestedSubzoneIdsField],
Expand Down
27 changes: 27 additions & 0 deletions src/main/resources/db/migration/0300/V326__AdHocPlots.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
CREATE TABLE tracking.observation_types (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
);

INSERT INTO tracking.observation_types (id, name)
VALUES (1, 'Monitoring'),
(2, 'Biomass Measurements')
ON CONFLICT (id) DO UPDATE SET name = excluded.name;

ALTER TABLE tracking.observations ADD COLUMN observation_type_id INTEGER REFERENCES tracking.observation_types;
UPDATE tracking.observations
SET observation_type_id = 1
WHERE observation_type_id IS NULL;
ALTER TABLE tracking.observations ALTER COLUMN observation_type_id SET NOT NULL;

ALTER TABLE tracking.observations ADD COLUMN is_ad_hoc BOOLEAN;
UPDATE tracking.observations
SET is_ad_hoc = false
WHERE is_ad_hoc IS NULL;
ALTER TABLE tracking.observations ALTER COLUMN is_ad_hoc SET NOT NULL;

ALTER TABLE tracking.monitoring_plots ADD COLUMN is_ad_hoc BOOLEAN;
UPDATE tracking.monitoring_plots
SET is_ad_hoc = false
WHERE is_ad_hoc IS NULL;
ALTER TABLE tracking.monitoring_plots ALTER COLUMN is_ad_hoc SET NOT NULL;
2 changes: 2 additions & 0 deletions src/main/resources/db/migration/R__Comments.sql
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ COMMENT ON TABLE tracking.observation_requested_subzones IS 'If an observation s

COMMENT ON TABLE tracking.observation_states IS '(Enum) Where in the observation lifecycle a particular observation is.';

COMMENT ON TABLE tracking.observation_types IS '(Enum) Type of observation, currently only used for ad hoc observations.';

COMMENT ON TABLE tracking.observations IS 'Scheduled observations of planting sites. This table may contain rows describing future observations as well as current and past ones.';
COMMENT ON COLUMN tracking.observations.completed_time IS 'Server-generated date and time the final piece of data for the observation was received.';
COMMENT ON COLUMN tracking.observations.end_date IS 'Last day of the observation. This is typically the last day of the same month as `start_date`.';
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/db/migration/R__TypeCodes.sql
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ VALUES (1, 'Upcoming'),
(5, 'Abandoned')
ON CONFLICT (id) DO UPDATE SET name = excluded.name;

INSERT INTO tracking.observation_types (id, name)
VALUES (1, 'Monitoring'),
(2, 'Biomass Measurements')
ON CONFLICT (id) DO UPDATE SET name = excluded.name;

INSERT INTO organization_types (id, name)
VALUES (1, 'Government'),
(2, 'NGO'),
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/i18n/Enums_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,5 @@ tracking.PlantingType.Delivery=Delivery
tracking.PlantingType.ReassignmentFrom=Reassignment From
tracking.PlantingType.ReassignmentTo=Reassignment To
tracking.PlantingType.Undo=Undo
tracking.ObservationType.BiomassMeasurements=Biomass Measurements
tracking.ObservationType.Monitoring=Monitoring
4 changes: 4 additions & 0 deletions src/main/resources/i18n/Messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,8 @@ search.monitoringPlots.boundary=Monitoring plot boundary
search.monitoringPlots.createdTime=Monitoring plot created time
search.monitoringPlots.fullName=Monitoring plot full name
search.monitoringPlots.id=Monitoring plot ID
search.monitoringPlots.isAdHoc=Monitoring plot is ad-hoc
search.monitoringPlots.isAvailable=Monitoring plot is available
search.monitoringPlots.modifiedTime=Monitoring plot modified time
search.monitoringPlots.name=Monitoring plot name
search.monitoringPlots.northeastLatitude=Northeast corner latitude
Expand Down Expand Up @@ -571,8 +573,10 @@ search.observations.completedTime=Observation completed time
search.observations.createdTime=Observation created time
search.observations.endDate=Observation end date
search.observations.id=Observation ID
search.observations.isAdHoc=Observation is ad-hoc
search.observations.plantingSiteHistoryId=Observation planting site history ID
search.observations.startDate=Observation start date
search.observations.type=Observation type
search.organizationInternalTags.name=Organization internal tag name
search.organizationUsers.createdTime=Organization membership creation time
search.organizationUsers.roleName=User role name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import com.terraformation.backend.db.default_schema.tables.pojos.NotificationsRo
import com.terraformation.backend.db.docprod.VariableType
import com.terraformation.backend.db.nursery.tables.pojos.BatchesRow
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.device.db.DeviceStore
import com.terraformation.backend.device.event.DeviceUnresponsiveEvent
import com.terraformation.backend.device.event.SensorBoundsAlertTriggeredEvent
Expand Down Expand Up @@ -509,6 +510,8 @@ internal class AppNotificationServiceTest : DatabaseTest(), RunsAsUser {
ExistingObservationModel(
endDate = endDate,
id = inserted.observationId,
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = inserted.plantingSiteId,
startDate = startDate,
state = ObservationState.InProgress)))
Expand Down Expand Up @@ -540,6 +543,8 @@ internal class AppNotificationServiceTest : DatabaseTest(), RunsAsUser {
ExistingObservationModel(
endDate = endDate,
id = inserted.observationId,
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = inserted.plantingSiteId,
startDate = startDate,
state = ObservationState.Upcoming)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationPlotPosition
import com.terraformation.backend.db.tracking.ObservationPlotStatus
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.ObservedPlotCoordinatesId
import com.terraformation.backend.db.tracking.PlantingId
import com.terraformation.backend.db.tracking.PlantingSeasonId
Expand Down Expand Up @@ -1942,6 +1943,7 @@ abstract class DatabaseBackedTest {
y.toDouble() * sizeMeters.toDouble()),
createdBy: UserId = row.createdBy ?: currentUser().userId,
createdTime: Instant = row.createdTime ?: Instant.EPOCH,
isAdHoc: Boolean = row.isAdHoc ?: false,
isAvailable: Boolean = row.isAvailable ?: true,
modifiedBy: UserId = row.modifiedBy ?: createdBy,
modifiedTime: Instant = row.modifiedTime ?: createdTime,
Expand All @@ -1961,6 +1963,7 @@ abstract class DatabaseBackedTest {
createdBy = createdBy,
createdTime = createdTime,
fullName = fullName,
isAdHoc = isAdHoc,
isAvailable = isAvailable,
modifiedBy = modifiedBy,
modifiedTime = modifiedTime,
Expand Down Expand Up @@ -2276,6 +2279,8 @@ abstract class DatabaseBackedTest {
row: ObservationsRow = ObservationsRow(),
createdTime: Instant = Instant.EPOCH,
endDate: LocalDate = row.endDate ?: LocalDate.of(2023, 1, 31),
isAdHoc: Boolean = row.isAdHoc ?: false,
observationType: ObservationType = row.observationTypeId ?: ObservationType.Monitoring,
plantingSiteId: PlantingSiteId = row.plantingSiteId ?: inserted.plantingSiteId,
startDate: LocalDate = row.startDate ?: LocalDate.of(2023, 1, 1),
completedTime: Instant? = row.completedTime,
Expand All @@ -2300,6 +2305,8 @@ abstract class DatabaseBackedTest {
completedTime = completedTime,
createdTime = createdTime,
endDate = endDate,
isAdHoc = isAdHoc,
observationTypeId = observationType,
plantingSiteHistoryId = plantingSiteHistoryId,
plantingSiteId = plantingSiteId,
startDate = startDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ class SchemaDocsGenerator : DatabaseTest() {
"observation_plots" to setOf(ALL, TRACKING),
"observation_requested_subzones" to setOf(ALL, TRACKING),
"observation_states" to setOf(ALL, TRACKING),
"observation_types" to setOf(ALL, TRACKING),
"observations" to setOf(ALL, TRACKING),
"observed_plot_coordinates" to setOf(ALL, TRACKING),
"observed_plot_species_totals" to setOf(ALL, TRACKING),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import com.terraformation.backend.db.seedbank.AccessionId
import com.terraformation.backend.db.tracking.MonitoringPlotId
import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.PlantingSeasonId
import com.terraformation.backend.db.tracking.PlantingSiteId
import com.terraformation.backend.device.db.DeviceStore
Expand Down Expand Up @@ -277,6 +278,8 @@ internal class EmailNotificationServiceTest {
ExistingObservationModel(
endDate = LocalDate.of(2023, 9, 30),
id = ObservationId(1),
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = plantingSite.id,
startDate = LocalDate.of(2023, 9, 1),
state = ObservationState.Upcoming)
Expand Down Expand Up @@ -564,6 +567,8 @@ internal class EmailNotificationServiceTest {
ExistingObservationModel(
endDate = LocalDate.of(2023, 9, 30),
id = ObservationId(1),
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = plantingSite.id,
startDate = LocalDate.of(2023, 9, 1),
state = ObservationState.InProgress))
Expand Down Expand Up @@ -626,6 +631,8 @@ internal class EmailNotificationServiceTest {
ExistingObservationModel(
endDate = LocalDate.of(2023, 10, 31),
id = ObservationId(1),
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteId = plantingSite.id,
startDate = LocalDate.of(2023, 10, 1),
state = ObservationState.Upcoming))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.terraformation.backend.db.tracking.MonitoringPlotId
import com.terraformation.backend.db.tracking.ObservationId
import com.terraformation.backend.db.tracking.ObservationPlotPosition
import com.terraformation.backend.db.tracking.ObservationState
import com.terraformation.backend.db.tracking.ObservationType
import com.terraformation.backend.db.tracking.PlantingSiteId
import com.terraformation.backend.db.tracking.PlantingSubzoneId
import com.terraformation.backend.db.tracking.RecordedSpeciesCertainty.Known
Expand Down Expand Up @@ -955,6 +956,8 @@ class ObservationServiceTest : DatabaseTest(), RunsAsDatabaseUser {
NewObservationModel(
plantingSiteId = plantingSiteId,
id = null,
isAdHoc = false,
observationType = ObservationType.Monitoring,
startDate = startDate,
endDate = endDate,
state = ObservationState.Upcoming,
Expand Down Expand Up @@ -1767,6 +1770,8 @@ class ObservationServiceTest : DatabaseTest(), RunsAsDatabaseUser {
ExistingObservationModel(
endDate = LocalDate.of(2023, 1, 31),
id = observationId,
isAdHoc = false,
observationType = ObservationType.Monitoring,
plantingSiteHistoryId = inserted.plantingSiteHistoryId,
plantingSiteId = inserted.plantingSiteId,
startDate = LocalDate.of(2023, 1, 1),
Expand Down
Loading

0 comments on commit 88ebbcd

Please sign in to comment.