ActivitySummary
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
package com.peakup.activity.dao;
|
||||
|
||||
import com.peakup.activity.model.ActivitySummary;
|
||||
import com.peakup.activity.model.ActivitySummary_;
|
||||
import com.peakup.common.dao.AbstractTimestampedDAO;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ActivitySummaryDAO extends AbstractTimestampedDAO<ActivitySummary> {
|
||||
|
||||
@Override
|
||||
protected Class<ActivitySummary> getEntityClass() {
|
||||
return ActivitySummary.class;
|
||||
}
|
||||
|
||||
public List<ActivitySummary> getByAthleteId(final Long athleteId) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<ActivitySummary> cq = cb.createQuery(ActivitySummary.class);
|
||||
final Root<ActivitySummary> root = cq.from(ActivitySummary.class);
|
||||
cq.select(root)
|
||||
.where(cb.equal(root.get(ActivitySummary_.athleteId), athleteId))
|
||||
.orderBy(cb.desc(root.get(ActivitySummary_.startTime)));
|
||||
return em.createQuery(cq).getResultList();
|
||||
}
|
||||
|
||||
public List<ActivitySummary> getByAthleteIdBetween(final Long athleteId, final Instant from, final Instant to) {
|
||||
final CriteriaBuilder cb = em.getCriteriaBuilder();
|
||||
final CriteriaQuery<ActivitySummary> cq = cb.createQuery(ActivitySummary.class);
|
||||
final Root<ActivitySummary> root = cq.from(ActivitySummary.class);
|
||||
cq.select(root)
|
||||
.where(
|
||||
cb.equal(root.get(ActivitySummary_.athleteId), athleteId),
|
||||
cb.greaterThanOrEqualTo(root.get(ActivitySummary_.startTime), from),
|
||||
cb.lessThan(root.get(ActivitySummary_.startTime), to)
|
||||
)
|
||||
.orderBy(cb.desc(root.get(ActivitySummary_.startTime)));
|
||||
return em.createQuery(cq).getResultList();
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.peakup.activity.mapper;
|
||||
|
||||
import com.peakup.activity.model.ActivitySummary;
|
||||
import com.peakup.activity.model.IntervalsActivity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@Mapper(
|
||||
componentModel = MappingConstants.ComponentModel.CDI,
|
||||
unmappedTargetPolicy = ReportingPolicy.ERROR,
|
||||
unmappedSourcePolicy = ReportingPolicy.IGNORE
|
||||
)
|
||||
public interface ActivitySummaryMapper {
|
||||
|
||||
private static void putIfNonZero(final Map<String, String> map, final String key, final @Nullable Double value) {
|
||||
if (value != null && value != 0.0) {
|
||||
map.put(key, String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
@Mapping(target = "activityId", expression = "java(source.getId() != null ? source.getId() : 0L)")
|
||||
@Mapping(target = "valuesForSummary", ignore = true)
|
||||
ActivitySummary toSummary(IntervalsActivity source);
|
||||
|
||||
@AfterMapping
|
||||
default void populateValuesForSummary(@MappingTarget final ActivitySummary target, final IntervalsActivity source) {
|
||||
final Map<String, String> values = new HashMap<>();
|
||||
putIfNonZero(values, "distanceM", source.getDistanceM());
|
||||
putIfNonZero(values, "averageHeartrateBpm", source.getAverageHeartrateBpm());
|
||||
putIfNonZero(values, "averagePowerWatt", source.getAveragePowerWatt());
|
||||
putIfNonZero(values, "normalizedPowerWatt", source.getNormalizedPowerWatt());
|
||||
putIfNonZero(values, "trainingLoad", source.getTrainingLoad());
|
||||
putIfNonZero(values, "ctl", source.getCtl());
|
||||
putIfNonZero(values, "atl", source.getAtl());
|
||||
putIfNonZero(values, "averageSpeedMps", source.getAverageSpeedMps());
|
||||
putIfNonZero(values, "paceMps", source.getPaceMps());
|
||||
target.setValuesForSummary(values);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
@com.peakup.common.annotation.NonNull
|
||||
package com.peakup.activity.mapper;
|
||||
@@ -17,28 +17,28 @@ import java.time.Instant;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public abstract class AbstractActivity extends AbstractTimestampedEntity {
|
||||
|
||||
@Column
|
||||
@Column(name = "athlete_id")
|
||||
private Long athleteId;
|
||||
|
||||
@Column
|
||||
@Column(name = "origin_id")
|
||||
public String originId;
|
||||
|
||||
@Column
|
||||
@Column(name = "name")
|
||||
public String name;
|
||||
|
||||
@Column
|
||||
@Column(name = "type")
|
||||
public String type;
|
||||
|
||||
@Column
|
||||
@Column(name = "sport_type")
|
||||
public String sportType;
|
||||
|
||||
@Column
|
||||
@Column(name = "activity_type")
|
||||
public ActivityTypeEnum activityType;
|
||||
|
||||
@Column
|
||||
@Column(name = "start_time")
|
||||
public Instant startTime;
|
||||
|
||||
@Column
|
||||
@Column(name = "timezone")
|
||||
public String timezone;
|
||||
|
||||
@Column(name = "distance_m")
|
||||
@@ -68,22 +68,22 @@ public abstract class AbstractActivity extends AbstractTimestampedEntity {
|
||||
@Column(name = "average_cadence_rpm")
|
||||
public Double averageCadenceRPM;
|
||||
|
||||
@Column
|
||||
@Column(name = "average_power_watt")
|
||||
public Double averagePowerWatt;
|
||||
|
||||
@Column
|
||||
@Column(name = "max_power_watt")
|
||||
public Double maxPowerWatt;
|
||||
|
||||
@Column
|
||||
@Column(name = "normalized_power_watt")
|
||||
public Double normalizedPowerWatt;
|
||||
|
||||
@Column(name = "total_work_kj")
|
||||
public Double totalWorkKJ;
|
||||
|
||||
@Column
|
||||
@Column(name = "calories")
|
||||
public Double calories;
|
||||
|
||||
@Column
|
||||
@Column(name = "linked_workout_id")
|
||||
public @Nullable Long linkedWorkoutId;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -12,25 +12,25 @@ public class ActivityAchievement {
|
||||
@Column(name = "achievement_id")
|
||||
public @Nullable String achievementId;
|
||||
|
||||
@Column
|
||||
@Column(name = "type")
|
||||
public @Nullable String type;
|
||||
|
||||
@Column
|
||||
@Column(name = "message")
|
||||
public @Nullable String message;
|
||||
|
||||
@Column
|
||||
@Column(name = "watts")
|
||||
public @Nullable Integer watts;
|
||||
|
||||
@Column
|
||||
@Column(name = "secs")
|
||||
public @Nullable Integer secs;
|
||||
|
||||
@Column
|
||||
@Column(name = "value")
|
||||
public @Nullable Integer value;
|
||||
|
||||
@Column
|
||||
@Column(name = "distance")
|
||||
public @Nullable Double distance;
|
||||
|
||||
@Column
|
||||
@Column(name = "pace")
|
||||
public @Nullable Double pace;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -12,13 +12,13 @@ public class ActivityAttachment {
|
||||
@Column(name = "attachment_id")
|
||||
public @Nullable String attachmentId;
|
||||
|
||||
@Column
|
||||
@Column(name = "filename")
|
||||
public @Nullable String filename;
|
||||
|
||||
@Column
|
||||
@Column(name = "mimetype")
|
||||
public @Nullable String mimetype;
|
||||
|
||||
@Column
|
||||
@Column(name = "url")
|
||||
public @Nullable String url;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -22,13 +22,13 @@ import java.time.Instant;
|
||||
public class ActivityMapStreamPoint extends AbstractStream implements DependentEntity {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false)
|
||||
@Column(name = "activity_id", nullable = false)
|
||||
private long activityId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "lat", nullable = false)
|
||||
private double lat;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "lng", nullable = false)
|
||||
private double lng;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.time.Instant;
|
||||
public class ActivityStreamPoint extends AbstractStream implements DependentEntity {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false)
|
||||
@Column(name = "activity_id", nullable = false)
|
||||
private long activityId;
|
||||
|
||||
@Column(name = "elapsed_s", nullable = false)
|
||||
@@ -38,7 +38,7 @@ public class ActivityStreamPoint extends AbstractStream implements DependentEnti
|
||||
@Column(name = "heartrate_bpm")
|
||||
private @Nullable Integer heartrateBpm;
|
||||
|
||||
@Column
|
||||
@Column(name = "watts")
|
||||
private @Nullable Integer watts;
|
||||
|
||||
@Column(name = "torque_nm")
|
||||
@@ -50,10 +50,10 @@ public class ActivityStreamPoint extends AbstractStream implements DependentEnti
|
||||
@Column(name = "velocity_mps")
|
||||
private @Nullable Double velocityMps;
|
||||
|
||||
@Column
|
||||
@Column(name = "lat")
|
||||
private @Nullable Double lat;
|
||||
|
||||
@Column
|
||||
@Column(name = "lng")
|
||||
private @Nullable Double lng;
|
||||
|
||||
@Column(name = "temp_c")
|
||||
@@ -62,7 +62,7 @@ public class ActivityStreamPoint extends AbstractStream implements DependentEnti
|
||||
@Column(name = "grade_smooth")
|
||||
private @Nullable Double gradeSmooth;
|
||||
|
||||
@Column
|
||||
@Column(name = "moving")
|
||||
private @Nullable Boolean moving;
|
||||
|
||||
@Column(name = "lr_balance")
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
package com.peakup.activity.model;
|
||||
|
||||
import com.peakup.common.model.AbstractDataObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import com.peakup.common.model.AbstractTimestampedEntity;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Transient;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.annotations.Subselect;
|
||||
import org.hibernate.annotations.Synchronize;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Immutable
|
||||
@Subselect(ActivitySummary.QUERY)
|
||||
@Synchronize("intervals_activity")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ActivitySummary extends AbstractDataObject {
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ActivitySummary extends AbstractTimestampedEntity {
|
||||
|
||||
public ActivityTypeEnum activityType;
|
||||
public Instant startTime;
|
||||
public Long movingTimeS;
|
||||
public Double calories;
|
||||
private long activityId;
|
||||
public static final String QUERY = "SELECT ID, athlete_id, activity_type, start_time, moving_time_s, calories, name, modified_at, created_at FROM intervals_activity";
|
||||
|
||||
@Column(name = "athlete_id")
|
||||
private Long athleteId;
|
||||
|
||||
@Column(name = "activity_type")
|
||||
private ActivityTypeEnum activityType;
|
||||
|
||||
@Column(name = "start_time")
|
||||
private Instant startTime;
|
||||
|
||||
@Column(name = "moving_time_s")
|
||||
private Long movingTimeS;
|
||||
|
||||
@Column(name = "calories")
|
||||
private Double calories;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
private Map<String, String> valuesForSummary;
|
||||
|
||||
@Transient
|
||||
private @Nullable Map<String, String> valuesForSummary;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
public ActivitySummary() {
|
||||
// hibernate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ActivityZone {
|
||||
@Column(name = "value_end")
|
||||
public double valueEnd;
|
||||
|
||||
@Column
|
||||
@Column(name = "secs")
|
||||
public int secs;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -15,13 +15,13 @@ public class IgnorePart {
|
||||
@Column(name = "end_index")
|
||||
public int endIndex;
|
||||
|
||||
@Column
|
||||
@Column(name = "power")
|
||||
public @Nullable Boolean power;
|
||||
|
||||
@Column
|
||||
@Column(name = "pace")
|
||||
public @Nullable Boolean pace;
|
||||
|
||||
@Column
|
||||
@Column(name = "hr")
|
||||
public @Nullable Boolean hr;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -24,31 +24,31 @@ import java.util.List;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class IntervalsActivity extends AbstractActivity {
|
||||
|
||||
@Column
|
||||
@Column(name = "strava_origin_id")
|
||||
public String stravaOriginId;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "description", columnDefinition = "TEXT")
|
||||
public @Nullable String description;
|
||||
|
||||
@Column
|
||||
@Column(name = "trainer")
|
||||
public @Nullable Boolean trainer;
|
||||
|
||||
@Column
|
||||
@Column(name = "commute")
|
||||
public @Nullable Boolean commute;
|
||||
|
||||
@Column
|
||||
@Column(name = "race")
|
||||
public @Nullable Boolean race;
|
||||
|
||||
@Column
|
||||
@Column(name = "gear_id")
|
||||
public String gearId;
|
||||
|
||||
@Column
|
||||
@Column(name = "gear_name")
|
||||
public @Nullable String gearName;
|
||||
|
||||
@Column(name = "gear_distance_m")
|
||||
public @Nullable Double gearDistanceM;
|
||||
|
||||
@Column
|
||||
@Column(name = "gear_primary")
|
||||
public @Nullable Boolean gearPrimary;
|
||||
|
||||
@Column(name = "total_ascent_m")
|
||||
@@ -63,31 +63,31 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "max_altitude_m")
|
||||
public Double maxAltitudeM;
|
||||
|
||||
@Column
|
||||
@Column(name = "training_load")
|
||||
public Double trainingLoad;
|
||||
|
||||
@Column
|
||||
@Column(name = "intensity_factor")
|
||||
public Double intensityFactor;
|
||||
|
||||
@Column
|
||||
@Column(name = "efficiency_factor")
|
||||
public Double efficiencyFactor;
|
||||
|
||||
@Column
|
||||
@Column(name = "ftp")
|
||||
public @Nullable Integer ftp;
|
||||
|
||||
@Column
|
||||
@Column(name = "atl")
|
||||
public Double atl;
|
||||
|
||||
@Column
|
||||
@Column(name = "ctl")
|
||||
public Double ctl;
|
||||
|
||||
@Column
|
||||
@Column(name = "hrr_bpm_drop")
|
||||
public @Nullable Double hrrBpmDrop;
|
||||
|
||||
@Column
|
||||
@Column(name = "hrr_start_bpm")
|
||||
public @Nullable Integer hrrStartBpm;
|
||||
|
||||
@Column
|
||||
@Column(name = "hrr_end_bpm")
|
||||
public @Nullable Integer hrrEndBpm;
|
||||
|
||||
@Column(name = "hrr_start_time_s")
|
||||
@@ -96,16 +96,16 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "hrr_end_time_s")
|
||||
public @Nullable Integer hrrEndTimeSec;
|
||||
|
||||
@Column
|
||||
@Column(name = "hrr_average_watts")
|
||||
public @Nullable Integer hrrAverageWatts;
|
||||
|
||||
@Column
|
||||
@Column(name = "variability_index")
|
||||
public Double variabilityIndex;
|
||||
|
||||
@Column
|
||||
@Column(name = "feel")
|
||||
public @Nullable Integer feel;
|
||||
|
||||
@Column
|
||||
@Column(name = "perceived_exertion")
|
||||
public Double perceivedExertion;
|
||||
|
||||
@Column(name = "average_stride_length_m")
|
||||
@@ -114,7 +114,7 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "average_temp_c")
|
||||
public Double averageTempC;
|
||||
|
||||
@Column(columnDefinition = "integer[]")
|
||||
@Column(name = "recording_stops", columnDefinition = "integer[]")
|
||||
@JdbcTypeCode(SqlTypes.ARRAY)
|
||||
public @Nullable int[] recordingStops;
|
||||
|
||||
@@ -153,39 +153,39 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "max_temp_c")
|
||||
public @Nullable Double maxTempC;
|
||||
|
||||
@Column
|
||||
@Column(name = "avg_lr_balance")
|
||||
public @Nullable Double avgLrBalance;
|
||||
|
||||
// --- Grade Adjusted Pace ---
|
||||
@Column(name = "gap_mps")
|
||||
public @Nullable Double gapMps;
|
||||
|
||||
@Column
|
||||
@Column(name = "gap_model")
|
||||
public @Nullable String gapModel;
|
||||
|
||||
// --- Device / equipment ---
|
||||
@Column
|
||||
@Column(name = "device_name")
|
||||
public @Nullable String deviceName;
|
||||
|
||||
@Column
|
||||
@Column(name = "device_watts")
|
||||
public @Nullable Boolean deviceWatts;
|
||||
|
||||
@Column
|
||||
@Column(name = "power_meter")
|
||||
public @Nullable String powerMeter;
|
||||
|
||||
@Column
|
||||
@Column(name = "power_meter_serial")
|
||||
public @Nullable String powerMeterSerial;
|
||||
|
||||
@Column
|
||||
@Column(name = "power_meter_battery")
|
||||
public @Nullable String powerMeterBattery;
|
||||
|
||||
@Column(name = "crank_length_mm")
|
||||
public @Nullable Double crankLengthMm;
|
||||
|
||||
@Column
|
||||
@Column(name = "power_field")
|
||||
public @Nullable String powerField;
|
||||
|
||||
@Column
|
||||
@Column(name = "use_elevation_correction")
|
||||
public @Nullable Boolean useElevationCorrection;
|
||||
|
||||
// --- Nutrition ---
|
||||
@@ -197,7 +197,7 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
public @Nullable Double icuDistanceM;
|
||||
|
||||
// --- Time accounting ---
|
||||
@Column
|
||||
@Column(name = "icu_ignore_time")
|
||||
public @Nullable Boolean icuIgnoreTime;
|
||||
|
||||
@Column(name = "icu_recording_time_s")
|
||||
@@ -213,35 +213,35 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
public @Nullable Integer icuCooldownTimeS;
|
||||
|
||||
// --- Activity sub-type and pairing ---
|
||||
@Column
|
||||
@Column(name = "sub_type")
|
||||
public @Nullable String subType;
|
||||
|
||||
@Column
|
||||
@Column(name = "paired_event_id")
|
||||
public @Nullable String pairedEventId;
|
||||
|
||||
// --- Athlete state at activity time ---
|
||||
@Column(name = "icu_weight_kg")
|
||||
public @Nullable Double icuWeightKg;
|
||||
|
||||
@Column
|
||||
@Column(name = "lthr")
|
||||
public @Nullable Integer lthr;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_resting_hr")
|
||||
public @Nullable Integer icuRestingHr;
|
||||
|
||||
@Column(name = "threshold_pace_mps")
|
||||
public @Nullable Double thresholdPaceMps;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_power_spike_threshold")
|
||||
public @Nullable Integer icuPowerSpikeThreshold;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_sweet_spot_min")
|
||||
public @Nullable Double icuSweetSpotMin;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_sweet_spot_max")
|
||||
public @Nullable Double icuSweetSpotMax;
|
||||
|
||||
@Column
|
||||
@Column(name = "trimp")
|
||||
public @Nullable Double trimp;
|
||||
|
||||
// --- W' and P-max ---
|
||||
@@ -252,7 +252,7 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
public @Nullable Integer pMaxWatt;
|
||||
|
||||
// --- Performance model (PM) ---
|
||||
@Column
|
||||
@Column(name = "icu_pm_cp")
|
||||
public @Nullable Integer icuPmCp;
|
||||
|
||||
@Column(name = "icu_pm_w_prime_j")
|
||||
@@ -261,17 +261,17 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "icu_pm_p_max_watt")
|
||||
public @Nullable Integer icuPmPMaxWatt;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_pm_ftp")
|
||||
public @Nullable Integer icuPmFtp;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_pm_ftp_secs")
|
||||
public @Nullable Integer icuPmFtpSecs;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_pm_ftp_watts")
|
||||
public @Nullable Integer icuPmFtpWatts;
|
||||
|
||||
// --- Rolling performance ---
|
||||
@Column
|
||||
@Column(name = "icu_rolling_cp")
|
||||
public @Nullable Integer icuRollingCp;
|
||||
|
||||
@Column(name = "icu_rolling_w_prime_j")
|
||||
@@ -280,14 +280,14 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "icu_rolling_p_max_watt")
|
||||
public @Nullable Integer icuRollingPMaxWatt;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_rolling_ftp")
|
||||
public @Nullable Integer icuRollingFtp;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_rolling_ftp_delta")
|
||||
public @Nullable Integer icuRollingFtpDelta;
|
||||
|
||||
// --- Sweet-spot CP model ---
|
||||
@Column
|
||||
@Column(name = "ss_cp")
|
||||
public @Nullable Integer ssCp;
|
||||
|
||||
@Column(name = "ss_w_prime_j")
|
||||
@@ -297,176 +297,176 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
public @Nullable Integer ssPMaxWatt;
|
||||
|
||||
// --- Ignore flags ---
|
||||
@Column
|
||||
@Column(name = "icu_ignore_power")
|
||||
public @Nullable Boolean icuIgnorePower;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_ignore_hr")
|
||||
public @Nullable Boolean icuIgnoreHr;
|
||||
|
||||
@Column
|
||||
@Column(name = "ignore_velocity")
|
||||
public @Nullable Boolean ignoreVelocity;
|
||||
|
||||
@Column
|
||||
@Column(name = "ignore_pace")
|
||||
public @Nullable Boolean ignorePace;
|
||||
|
||||
// --- Activity flags ---
|
||||
@Column
|
||||
@Column(name = "has_heartrate")
|
||||
public @Nullable Boolean hasHeartrate;
|
||||
|
||||
@Column
|
||||
@Column(name = "analyzed")
|
||||
public @Nullable String analyzed;
|
||||
|
||||
@Column
|
||||
@Column(name = "has_weather")
|
||||
public @Nullable Boolean hasWeather;
|
||||
|
||||
@Column
|
||||
@Column(name = "has_segments")
|
||||
public @Nullable Boolean hasSegments;
|
||||
|
||||
// --- File / sync metadata ---
|
||||
@Column
|
||||
@Column(name = "file_type")
|
||||
public @Nullable String fileType;
|
||||
|
||||
@Column
|
||||
@Column(name = "file_sport_index")
|
||||
public @Nullable Integer fileSportIndex;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_athlete_id")
|
||||
public @Nullable String icuAthleteId;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_created")
|
||||
public @Nullable String icuCreated;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_sync_date")
|
||||
public @Nullable String icuSyncDate;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_chat_id")
|
||||
public @Nullable Long icuChatId;
|
||||
|
||||
// --- Local-timezone start ---
|
||||
@Column
|
||||
@Column(name = "start_date_local")
|
||||
public @Nullable String startDateLocal;
|
||||
|
||||
// --- Zone definitions (JSON) ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_hr_zones", columnDefinition = "TEXT")
|
||||
public @Nullable String icuHrZones;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "pace_zones", columnDefinition = "TEXT")
|
||||
public @Nullable String paceZones;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_power_zones", columnDefinition = "TEXT")
|
||||
public @Nullable String icuPowerZones;
|
||||
|
||||
// --- Complex nested data (JSON) ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_training_load_data", columnDefinition = "TEXT")
|
||||
public @Nullable String icuTrainingLoadData;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "interval_summary", columnDefinition = "TEXT")
|
||||
public @Nullable String intervalSummary;
|
||||
|
||||
// --- Available stream names ---
|
||||
@Column(columnDefinition = "text[]")
|
||||
@Column(name = "stream_types", columnDefinition = "text[]")
|
||||
@JdbcTypeCode(SqlTypes.ARRAY)
|
||||
public @Nullable String[] streamTypes;
|
||||
|
||||
// --- Skyline chart ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "skyline_chart_bytes", columnDefinition = "TEXT")
|
||||
public @Nullable String skylineChartBytes;
|
||||
|
||||
// --- Zone times (JSON) ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_zone_times", columnDefinition = "TEXT")
|
||||
public @Nullable String icuZoneTimes;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_hr_zone_times", columnDefinition = "TEXT")
|
||||
public @Nullable String icuHrZoneTimes;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "pace_zone_times", columnDefinition = "TEXT")
|
||||
public @Nullable String paceZoneTimes;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "gap_zone_times", columnDefinition = "TEXT")
|
||||
public @Nullable String gapZoneTimes;
|
||||
|
||||
@Column
|
||||
@Column(name = "use_gap_zone_times")
|
||||
public @Nullable Boolean useGapZoneTimes;
|
||||
|
||||
@Column
|
||||
@Column(name = "tiz_order")
|
||||
public @Nullable String tizOrder;
|
||||
|
||||
// --- Performance / load metrics ---
|
||||
@Column
|
||||
@Column(name = "polarization_index")
|
||||
public @Nullable Double polarizationIndex;
|
||||
|
||||
@Column
|
||||
@Column(name = "decoupling")
|
||||
public @Nullable Double decoupling;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_lap_count")
|
||||
public @Nullable Integer icuLapCount;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_joules_above_ftp")
|
||||
public @Nullable Integer icuJoulesAboveFtp;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_max_wbal_depletion")
|
||||
public @Nullable Integer icuMaxWbalDepletion;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_power_hr_z2")
|
||||
public @Nullable Double icuPowerHrZ2;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_power_hr_z2_mins")
|
||||
public @Nullable Integer icuPowerHrZ2Mins;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_cadence_z2")
|
||||
public @Nullable Double icuCadenceZ2;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_rpe")
|
||||
public @Nullable Double icuRpe;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_power_hr")
|
||||
public @Nullable Double icuPowerHr;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_median_time_delta")
|
||||
public @Nullable Integer icuMedianTimeDelta;
|
||||
|
||||
@Column
|
||||
@Column(name = "p30s_exponent")
|
||||
public @Nullable Double p30sExponent;
|
||||
|
||||
// --- Intervals editing ---
|
||||
@Column
|
||||
@Column(name = "icu_intervals_edited")
|
||||
public @Nullable Boolean icuIntervalsEdited;
|
||||
|
||||
@Column
|
||||
@Column(name = "lock_intervals")
|
||||
public @Nullable Boolean lockIntervals;
|
||||
|
||||
@Column
|
||||
@Column(name = "workout_shift_secs")
|
||||
public @Nullable Integer workoutShiftSecs;
|
||||
|
||||
// --- Swimming ---
|
||||
@Column(name = "pool_length_m")
|
||||
public @Nullable Integer poolLengthM;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "lengths", columnDefinition = "TEXT")
|
||||
public @Nullable String lengths;
|
||||
|
||||
// --- Load scores ---
|
||||
@Column
|
||||
@Column(name = "power_load")
|
||||
public @Nullable Double powerLoad;
|
||||
|
||||
@Column
|
||||
@Column(name = "hr_load")
|
||||
public @Nullable Double hrLoad;
|
||||
|
||||
@Column
|
||||
@Column(name = "pace_load")
|
||||
public @Nullable Double paceLoad;
|
||||
|
||||
@Column
|
||||
@Column(name = "hr_load_type")
|
||||
public @Nullable String hrLoadType;
|
||||
|
||||
@Column
|
||||
@Column(name = "pace_load_type")
|
||||
public @Nullable String paceLoadType;
|
||||
|
||||
@Column
|
||||
@Column(name = "session_rpe")
|
||||
public @Nullable Double sessionRpe;
|
||||
|
||||
@Column
|
||||
@Column(name = "strain_score")
|
||||
public @Nullable Double strainScore;
|
||||
|
||||
@Column
|
||||
@Column(name = "kg_lifted")
|
||||
public @Nullable Double kgLifted;
|
||||
|
||||
// --- Weather ---
|
||||
@@ -497,16 +497,16 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
@Column(name = "average_wind_gust_mps")
|
||||
public @Nullable Double averageWindGustMps;
|
||||
|
||||
@Column
|
||||
@Column(name = "prevailing_wind_deg")
|
||||
public @Nullable Double prevailingWindDeg;
|
||||
|
||||
@Column
|
||||
@Column(name = "headwind_percent")
|
||||
public @Nullable Double headwindPercent;
|
||||
|
||||
@Column
|
||||
@Column(name = "tailwind_percent")
|
||||
public @Nullable Double tailwindPercent;
|
||||
|
||||
@Column
|
||||
@Column(name = "average_clouds")
|
||||
public @Nullable Double averageClouds;
|
||||
|
||||
@Column(name = "max_rain_mm")
|
||||
@@ -524,50 +524,50 @@ public class IntervalsActivity extends AbstractActivity {
|
||||
public @Nullable Double paceMps;
|
||||
|
||||
// --- Athlete / HR ---
|
||||
@Column
|
||||
@Column(name = "athlete_max_hr")
|
||||
public @Nullable Integer athleteMaxHr;
|
||||
|
||||
// --- Coach / compliance ---
|
||||
@Column
|
||||
@Column(name = "compliance")
|
||||
public @Nullable String compliance;
|
||||
|
||||
@Column
|
||||
@Column(name = "coach_tick")
|
||||
public @Nullable Boolean coachTick;
|
||||
|
||||
@Column(name = "activity_group")
|
||||
public @Nullable String activityGroup;
|
||||
|
||||
// --- Source / sync metadata ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "icu_sync_error", columnDefinition = "TEXT")
|
||||
public @Nullable String icuSyncError;
|
||||
|
||||
@Column
|
||||
@Column(name = "icu_color")
|
||||
public @Nullable String icuColor;
|
||||
|
||||
@Column
|
||||
@Column(name = "source")
|
||||
public @Nullable String source;
|
||||
|
||||
@Column
|
||||
@Column(name = "oauth_client_id")
|
||||
public @Nullable String oauthClientId;
|
||||
|
||||
@Column
|
||||
@Column(name = "oauth_client_name")
|
||||
public @Nullable String oauthClientName;
|
||||
|
||||
@Column
|
||||
@Column(name = "strava_id")
|
||||
public @Nullable Long stravaId;
|
||||
|
||||
@Column
|
||||
@Column(name = "route_id")
|
||||
public @Nullable Long routeId;
|
||||
|
||||
// --- Power field names ---
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "power_field_names", columnDefinition = "TEXT")
|
||||
public @Nullable String powerFieldNames;
|
||||
|
||||
// --- Stream import status ---
|
||||
@Column
|
||||
@Column(name = "stream_status")
|
||||
public StreamStatusEnum streamStatus = StreamStatusEnum.PENDING;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "stream_import_error", columnDefinition = "TEXT")
|
||||
public @Nullable String streamImportError;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -13,7 +13,7 @@ import lombok.EqualsAndHashCode;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class StravaActivity extends AbstractActivity {
|
||||
|
||||
@Column
|
||||
@Column(name = "device_name")
|
||||
public String deviceName;
|
||||
|
||||
@Convert(converter = IntervalsImportStatusEnum.Converter.class)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.peakup.activity.service;
|
||||
|
||||
import com.peakup.activity.dao.ActivitySummaryDAO;
|
||||
import com.peakup.activity.model.ActivitySummary;
|
||||
import com.peakup.common.service.AbstractService;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
@ApplicationScoped
|
||||
public class ActivitySummaryService extends AbstractService<ActivitySummary, ActivitySummaryDAO> {
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
ActivitySummaryDAO activitySummaryDAO;
|
||||
|
||||
@Override
|
||||
protected ActivitySummaryDAO getDAO() {
|
||||
return activitySummaryDAO;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<ActivitySummary> getByAthleteId(final Long athleteId) {
|
||||
return activitySummaryDAO.getByAthleteId(athleteId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<ActivitySummary> getByAthleteIdBetween(final Long athleteId, final String from, final String to) {
|
||||
final Instant fromInstant = LocalDate.parse(from).atStartOfDay(ZoneOffset.UTC).toInstant();
|
||||
final Instant toInstant = LocalDate.parse(to).plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant();
|
||||
return activitySummaryDAO.getByAthleteIdBetween(athleteId, fromInstant, toInstant);
|
||||
}
|
||||
}
|
||||
@@ -15,19 +15,19 @@ import lombok.EqualsAndHashCode;
|
||||
@AllArgsConstructor
|
||||
public class Athlete extends AbstractTimestampedEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "first_name", nullable = false)
|
||||
private String firstName;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "last_name", nullable = false)
|
||||
private String lastName;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "login", nullable = false)
|
||||
private String login;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "email", nullable = false)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "weight", nullable = false)
|
||||
private Double weight;
|
||||
|
||||
@Convert(converter = SexEnum.Converter.class)
|
||||
|
||||
@@ -13,7 +13,7 @@ import java.time.Instant;
|
||||
public abstract class AbstractTimescaleEntity {
|
||||
|
||||
@Id
|
||||
@Column(nullable = false)
|
||||
@Column(name = "time", nullable = false)
|
||||
private Instant time;
|
||||
|
||||
protected AbstractTimescaleEntity() {
|
||||
|
||||
@@ -18,10 +18,10 @@ import java.time.Instant;
|
||||
@AllArgsConstructor
|
||||
public abstract class AbstractTimestampedEntity extends AbstractEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "modified_at", nullable = false)
|
||||
private Instant modifiedAt = Instant.now();
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "created_at", nullable = false)
|
||||
private Instant createdAt = Instant.now();
|
||||
|
||||
@PrePersist
|
||||
|
||||
@@ -14,13 +14,13 @@ import lombok.EqualsAndHashCode;
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
public class IntervalsConnector extends AbstractTimestampedEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "athlete_id", nullable = false)
|
||||
private Long athleteId; // loose coupling to Athlete
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "intervals_athlete_id", nullable = false)
|
||||
private String intervalsAthleteId; // e.g. "i_1234567"
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "api_key", nullable = false)
|
||||
private String apiKey;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -14,25 +14,25 @@ import lombok.EqualsAndHashCode;
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
public class StravaConnector extends AbstractTimestampedEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "athlete_id", nullable = false)
|
||||
private Long athleteId; // loose coupling
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "strava_athlete_id", nullable = false)
|
||||
private String stravaAthleteId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "access_token", nullable = false)
|
||||
private String accessToken;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "refresh_token", nullable = false)
|
||||
private String refreshToken;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "expires_at", nullable = false)
|
||||
private long expiresAt;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "client_id", nullable = false)
|
||||
private String clientId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "client_secret", nullable = false)
|
||||
private String clientSecret;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.peakup.dashboard.service;
|
||||
|
||||
import com.peakup.activity.mapper.ActivitySummaryMapper;
|
||||
import com.peakup.activity.model.ActivityMapStreamPoint;
|
||||
import com.peakup.activity.model.ActivityStreamPoint;
|
||||
import com.peakup.activity.model.ActivitySummary;
|
||||
import com.peakup.activity.model.IntervalsActivity;
|
||||
import com.peakup.activity.service.ActivityMapStreamService;
|
||||
import com.peakup.activity.service.ActivityStreamService;
|
||||
import com.peakup.activity.service.IntervalsActivityService;
|
||||
import com.peakup.activity.service.ActivitySummaryService;
|
||||
import com.peakup.dashboard.model.Dashboard;
|
||||
import com.peakup.goal.service.GoalMetricPeriodTotalService;
|
||||
import com.peakup.goal.service.GoalService;
|
||||
@@ -30,7 +28,7 @@ public class DashboardService {
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
IntervalsActivityService intervalsActivityService;
|
||||
ActivitySummaryService activitySummaryService;
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
@@ -48,10 +46,6 @@ public class DashboardService {
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
GoalMetricPeriodTotalService goalMetricPeriodTotalService;
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
ActivitySummaryMapper activitySummaryMapper;
|
||||
|
||||
@Transactional
|
||||
public Dashboard getDashboard(final long athleteId, final int calendarWeek, final int year) {
|
||||
final LocalDate selectedWeekMonday = LocalDate.now()
|
||||
@@ -65,14 +59,11 @@ public class DashboardService {
|
||||
final String from = rangeFrom.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
final String to = rangeTo.format(DateTimeFormatter.ISO_LOCAL_DATE);
|
||||
|
||||
final List<IntervalsActivity> activities = intervalsActivityService.getByAthleteIdBetween(athleteId, from, to);
|
||||
final List<ActivitySummary> activitySummaries = activitySummaryService.getByAthleteIdBetween(athleteId, from, to);
|
||||
final Map<Long, List<ActivityMapStreamPoint>> weekActivityMapStreams =
|
||||
resolveWeekActivityMapStreams(activities, selectedWeekMonday);
|
||||
resolveWeekActivityMapStreams(activitySummaries, selectedWeekMonday);
|
||||
final Map<Long, List<ActivityStreamPoint>> weekActivityStreams =
|
||||
resolveWeekActivityStreams(activities, selectedWeekMonday);
|
||||
final List<ActivitySummary> activitySummaries = activities.stream()
|
||||
.map(activitySummaryMapper::toSummary)
|
||||
.toList();
|
||||
resolveWeekActivityStreams(activitySummaries, selectedWeekMonday);
|
||||
|
||||
return new Dashboard(
|
||||
calendarWeek,
|
||||
@@ -85,7 +76,7 @@ public class DashboardService {
|
||||
);
|
||||
}
|
||||
|
||||
private List<IntervalsActivity> filterToWeek(final List<IntervalsActivity> activities, final LocalDate weekMonday) {
|
||||
private List<ActivitySummary> filterToWeek(final List<ActivitySummary> activities, final LocalDate weekMonday) {
|
||||
final LocalDate weekSunday = weekMonday.plusDays(6);
|
||||
return activities.stream()
|
||||
.filter(activity -> {
|
||||
@@ -97,7 +88,7 @@ public class DashboardService {
|
||||
}
|
||||
|
||||
private Map<Long, List<ActivityMapStreamPoint>> resolveWeekActivityMapStreams(
|
||||
final List<IntervalsActivity> activities,
|
||||
final List<ActivitySummary> activities,
|
||||
final LocalDate weekMonday) {
|
||||
return filterToWeek(activities, weekMonday).stream()
|
||||
.collect(Collectors.toMap(
|
||||
@@ -108,7 +99,7 @@ public class DashboardService {
|
||||
}
|
||||
|
||||
private Map<Long, List<ActivityStreamPoint>> resolveWeekActivityStreams(
|
||||
final List<IntervalsActivity> activities,
|
||||
final List<ActivitySummary> activities,
|
||||
final LocalDate weekMonday) {
|
||||
return filterToWeek(activities, weekMonday).stream()
|
||||
.collect(Collectors.toMap(
|
||||
|
||||
@@ -13,16 +13,16 @@ import lombok.EqualsAndHashCode;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Goal extends AbstractTimestampedEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "athlete_id", nullable = false)
|
||||
public Long athleteId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "period", nullable = false)
|
||||
public GoalPeriodEnum period;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "metric", nullable = false)
|
||||
public GoalMetricEnum metric;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "target_value", nullable = false)
|
||||
public Double targetValue;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -18,10 +18,10 @@ public class GoalMetricPeriodTotal extends AbstractTimestampedEntity {
|
||||
@Column(name = "athlete_id", nullable = false)
|
||||
private Long athleteId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "metric", nullable = false)
|
||||
private GoalMetricEnum metric;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "period", nullable = false)
|
||||
private GoalPeriodEnum period;
|
||||
|
||||
@Column(name = "year", nullable = false)
|
||||
@@ -30,7 +30,7 @@ public class GoalMetricPeriodTotal extends AbstractTimestampedEntity {
|
||||
@Column(name = "calendar_week", nullable = false)
|
||||
private int calendarWeek;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "aggregated_value", nullable = false)
|
||||
private double aggregatedValue;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -21,19 +21,19 @@ import java.util.List;
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class WeekPlan extends AbstractTimestampedEntity {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "athlete_id", nullable = false)
|
||||
public Long athleteId;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "year", nullable = false)
|
||||
public int year;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "calendar_week", nullable = false)
|
||||
public int calendarWeek;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Column(name = "week_label", nullable = false)
|
||||
public String weekLabel;
|
||||
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
@Column(name = "week_description", columnDefinition = "TEXT", nullable = false)
|
||||
public String weekDescription;
|
||||
|
||||
@Transient
|
||||
|
||||
@@ -29,23 +29,23 @@ public class Workout extends AbstractEntity implements DependentEntity {
|
||||
|
||||
@Column(name = "week_plan_id", nullable = false)
|
||||
public long weekPlanId;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "title", nullable = false)
|
||||
public String title;
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
@Column(name = "description", columnDefinition = "TEXT", nullable = false)
|
||||
public String description = "";
|
||||
@Column(nullable = false)
|
||||
@Column(name = "workout_at", nullable = false)
|
||||
public Instant workoutAt;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "workout_type", nullable = false)
|
||||
public WorkoutTypeEnum workoutType;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
public int sortOrder;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "status", nullable = false)
|
||||
public WorkoutStatusEnum status = WorkoutStatusEnum.PLANNED;
|
||||
@Column(columnDefinition = "TEXT")
|
||||
@Column(name = "status_note", columnDefinition = "TEXT")
|
||||
public @Nullable String statusNote;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "estimated_time_seconds", nullable = false)
|
||||
public int estimatedTimeSeconds;
|
||||
@Column
|
||||
@Column(name = "estimated_tss")
|
||||
public @Nullable Integer estimatedTss;
|
||||
@OneToMany(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "workout_id")
|
||||
|
||||
@@ -17,15 +17,15 @@ public class WorkoutLoad extends AbstractEntity implements DependentEntity {
|
||||
|
||||
@Column(name = "load_id", nullable = false)
|
||||
public long stepId;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "sort_index", nullable = false)
|
||||
public int sortIndex;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "step_type", nullable = false)
|
||||
public WorkoutStepTypeEnum stepType;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "duration_seconds", nullable = false)
|
||||
public int durationSeconds;
|
||||
@Column
|
||||
@Column(name = "target_value_pct_start")
|
||||
public @Nullable Integer targetValuePctStart;
|
||||
@Column
|
||||
@Column(name = "target_value_pct_end")
|
||||
public @Nullable Integer targetValuePctEnd;
|
||||
|
||||
@SuppressWarnings("NullAway.Init")
|
||||
|
||||
@@ -25,15 +25,15 @@ public class WorkoutStep extends AbstractEntity implements DependentEntity {
|
||||
|
||||
@Column(name = "workout_id", nullable = false)
|
||||
public long workoutId;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "sort_index", nullable = false)
|
||||
public int sortIndex;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "label", nullable = false)
|
||||
public String label;
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
@Column(name = "description", columnDefinition = "TEXT", nullable = false)
|
||||
public String description = "";
|
||||
@Column(nullable = false)
|
||||
@Column(name = "intensity_reference", nullable = false)
|
||||
public IntensityReferenceEnum intensityReference;
|
||||
@Column(nullable = false)
|
||||
@Column(name = "repeat", nullable = false)
|
||||
public int repeat;
|
||||
@OneToMany(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "load_id")
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.peakup;
|
||||
|
||||
import com.tngtech.archunit.core.domain.JavaClasses;
|
||||
import com.tngtech.archunit.core.domain.JavaField;
|
||||
import com.tngtech.archunit.core.importer.ClassFileImporter;
|
||||
import com.tngtech.archunit.core.importer.ImportOption;
|
||||
import com.tngtech.archunit.lang.ArchCondition;
|
||||
import com.tngtech.archunit.lang.ConditionEvents;
|
||||
import com.tngtech.archunit.lang.SimpleConditionEvent;
|
||||
import jakarta.persistence.Column;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.fields;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods;
|
||||
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
|
||||
|
||||
@@ -128,6 +134,32 @@ class ArchitectureTest {
|
||||
.check(CLASSES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Every field annotated with {@code @Column} must declare an explicit {@code name}.
|
||||
* Prevents silent breakage when Hibernate's naming strategy differs from expectations.
|
||||
*/
|
||||
@Test
|
||||
void columnFieldsHaveExplicitName() {
|
||||
fields().that().areAnnotatedWith(Column.class)
|
||||
.should(new ArchCondition<>("have an explicit column name") {
|
||||
@Override
|
||||
public void check(final JavaField field, final ConditionEvents events) {
|
||||
final Column column = field.getAnnotationOfType(Column.class);
|
||||
if (column.name().isEmpty()) {
|
||||
final String snake = field.getName()
|
||||
.replaceAll("([A-Z])", "_$1").toLowerCase(java.util.Locale.ROOT);
|
||||
events.add(SimpleConditionEvent.violated(
|
||||
field,
|
||||
field.getOwner().getSimpleName() + "." + field.getName()
|
||||
+ " fix: @Column(name=\"" + snake + "\")"
|
||||
));
|
||||
}
|
||||
}
|
||||
})
|
||||
.because("add name=\"snake_case\" to every @Column — prevents Hibernate naming-strategy surprises")
|
||||
.check(CLASSES);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code @Transactional} is only permitted in service and importer classes.
|
||||
* Resources must delegate to services; base abstract classes must not carry it.
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
// GENERATED — do not edit manually.
|
||||
|
||||
import type { AbstractDataObjectDo } from './AbstractDataObjectDo';
|
||||
import type { AbstractTimestampedEntityDo } from './AbstractTimestampedEntityDo';
|
||||
import type { ActivityTypeEnum } from './ActivityTypeEnum';
|
||||
|
||||
export interface ActivitySummaryDo extends AbstractDataObjectDo {
|
||||
export interface ActivitySummaryDo extends AbstractTimestampedEntityDo {
|
||||
athleteId: number;
|
||||
activityType: ActivityTypeEnum;
|
||||
startTime: string;
|
||||
movingTimeS: number;
|
||||
calories: number;
|
||||
activityId: number;
|
||||
athleteId: number;
|
||||
name: string;
|
||||
valuesForSummary: Record<string, string>;
|
||||
valuesForSummary: Record<string, string> | null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user