SleepSession.java

package com.seebie.server.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;

import java.io.Serializable;
import java.time.LocalDateTime;

@Entity
@Table(name = "sleep_session")
public class SleepSession implements Serializable {

    /**
     * We should prefer SEQUENCE over IDENTITY. Hibernate silently disables batch inserts for IDENTITY generators.
     *
     * The SequenceGenerator allocationSize MUST match the increment of the sequence
     * A good explanation of how it works is here https://vladmihalcea.com/jpa-entity-identifier-sequence/
     * but in a nutshell JPA will get one sequence value and allocate more values itself internally
     * and when it needs more values will call the database sequence for the next value.
     *
     * Also note the batch size property spring.jpa.properties.hibernate.jdbc.batch_size=50
     *
     * Note that there's another optimization for using hilo,
     * see https://vladmihalcea.com/the-hilo-algorithm/
     *
     */
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sleep_session_generator")
    @SequenceGenerator(name="sleep_session_generator", sequenceName = "sleep_session_sequence", allocationSize = 50)
    @Column(name = "id", updatable = false, nullable = false)
    private Long id;

    @NotNull
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @NotNull
    private String notes = "";

    @Basic
    private int minutesAwake = 0;

    @Basic
    @NotNull
    private LocalDateTime startTime = LocalDateTime.now();

    @Basic
    @NotNull
    @Column(name="stop_time")
    private LocalDateTime stopTime = LocalDateTime.now();

    /**
     * We want to keep the duration in the database, so we can do things like query against it,
     * and have a constraint to ensure it is always correct.
     * And only calculated in one place so there is only one place to update the calculation.
     */
    @Column
    private int minutesAsleep;

    @NotNull
    private String zoneId;

    public SleepSession() {
        // no arg constructor is required by JPA
    }

    public Long getId() {
        return id;
    }

    public String getZoneId() {
        return zoneId;
    }

    public LocalDateTime getStartTime() {
        return startTime;
    }

    public LocalDateTime getStopTime() {
        return stopTime;
    }

    public int getMinutesAsleep() {
        return minutesAsleep;
    }

    public void setSleepData(int minutesAwake, String notes, LocalDateTime start, LocalDateTime stop, int minutesAsleep, String zoneId) {
        this.minutesAwake = minutesAwake;
        this.notes = notes;
        this.startTime = start;
        this.stopTime = stop;
        this.zoneId = zoneId;
        this.minutesAsleep = minutesAsleep;
    }

    public String getNotes() {
        return notes;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public int getMinutesAwake() {
        return minutesAwake;
    }

}