Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/support for networks #309

Merged
merged 24 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
86561ec
feat: Implement Network entity and update Person and Organization ent…
jungwire Apr 30, 2024
348237c
test: Add unit tests for Network entity
jungwire Apr 30, 2024
1d4947c
refactor: collections as part of networks rather than biobanks
jungwire May 2, 2024
a0afd92
refactor: Network class and for improved code readability and simplicity
jungwire May 2, 2024
f894c3a
feat: adds functions to add and remove manager
jungwire May 2, 2024
de57095
test: adds NetworkRepositoryTest
jungwire May 2, 2024
6288f47
feat: et minimal visibility for network constructors and move network…
jungwire May 2, 2024
30f5d55
feat: switch to lombok constructor and add JavaDoc comments
jungwire May 3, 2024
3fc76ca
feat: add network_person_link table
jungwire May 3, 2024
64595ad
docs: add javadoc for uri
jungwire May 6, 2024
6dd6cdb
fix: Sequence generator name
jungwire May 6, 2024
b0a1783
docs: fix javadocs form attributes and functions
jungwire May 6, 2024
8a8c20b
fix: changes NoArgsConstructor access to protected
jungwire May 8, 2024
57022df
fix: imports
jungwire May 8, 2024
25f839e
docs: adds entity javadocs
jungwire May 8, 2024
ef5b874
fix: imports
jungwire May 10, 2024
e27fd96
docs: adds javadocs for class
jungwire May 10, 2024
20c570b
test: adds for linking to resources and managers
jungwire May 10, 2024
3eca38e
test: for linking to resources and managers
jungwire May 10, 2024
a6cc19c
refactor: update Person, Resource and Network classes to manage relat…
jungwire May 10, 2024
995b4e3
refactor: update equals() and hashCode methods
jungwire May 10, 2024
09543c7
fix: imports
jungwire May 13, 2024
7d7f917
feat: switch associated resources from EAGER to LAZY fetching
jungwire May 13, 2024
cb2a44f
fix: network relationships to Person and Resource models
jungwire May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package eu.bbmri_eric.negotiator.database.model;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString.Exclude;

/**
* Represents a Network entity in the database. A Network has a unique identifier, a URI, a name, a
* contact email, a set of managers, and a set of resources.
*/
@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved
public class Network {
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "network_id_seq")
@SequenceGenerator(name = "network_id_seq", initialValue = 10000, allocationSize = 1)
private Long id;

/** The URI of the network */
@NotNull private String uri;

Check warning on line 35 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L35

Added line #L35 was not covered by tests
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved

/** The name of the network */
@Column(unique = true)
private String name;

Check warning on line 39 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L39

Added line #L39 was not covered by tests

/** A unique and persistent identifier issued by an appropriate institution */
@NotNull
@Column(unique = true)
private String externalId;

Check warning on line 44 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L44

Added line #L44 was not covered by tests

/** The contact email of the network. */
private String contactEmail;

Check warning on line 47 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L47

Added line #L47 was not covered by tests

/** The managers of the network. */
@ManyToMany(mappedBy = "networks")
@Exclude
@Setter(AccessLevel.NONE)
@Builder.Default
private Set<Person> managers = new HashSet<>();
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved

/** The resources of the network. */
@ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = FetchType.EAGER)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid eager fetching as much as possible since we will have some large objects. Any good reason for including it? A network can have thousands of resources

@JoinTable(
name = "network_resources_link",
joinColumns = @JoinColumn(name = "network_id"),
inverseJoinColumns = @JoinColumn(name = "resource_id"))
@Builder.Default
@Exclude
@Setter(AccessLevel.NONE)
private Set<Resource> resources = new HashSet<>();
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Network that = (Network) o;
return Objects.equals(externalId, that.externalId)
&& Objects.equals(id, that.id)
&& Objects.equals(uri, that.uri)
&& Objects.equals(name, that.name)
&& Objects.equals(contactEmail, that.contactEmail);
}

@Override
public int hashCode() {
return Objects.hash(externalId, id, uri, name, contactEmail);
}

/** Adds a resource to the network. */
public void addResource(Resource collection) {
resources.add(collection);
if (!collection.getNetworks().contains(this)) {
collection.addNetwork(this);
}
}

/** Removes a resource from the network. */
public void removeResource(Resource collection) {
resources.remove(collection);
if (collection.getNetworks().contains(this)) {
collection.removeNetwork(this);
}
}

/** Returns all resources in the network. */
public Set<Resource> getResources() {
if (Objects.isNull(this.resources)) {
return Set.of();

Check warning on line 105 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L105

Added line #L105 was not covered by tests
}
return Collections.unmodifiableSet(this.resources);
}

/** Adds a manager to the network. */
public void addManager(Person manager) {
managers.add(manager);
if (!manager.getNetworks().contains(this)) {
manager.addNetwork(this);
}
}

/** Removes a manager from the network. */
public void removeManager(Person manager) {
managers.remove(manager);

Check warning on line 120 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L120

Added line #L120 was not covered by tests
if (manager.getNetworks().contains(this)) {
manager.removeNetwork(this);

Check warning on line 122 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L122

Added line #L122 was not covered by tests
}
}

Check warning on line 124 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L124

Added line #L124 was not covered by tests

public Set<Person> getManagers() {
if (Objects.isNull(this.managers)) {
return Set.of();

Check warning on line 128 in src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Network.java#L128

Added line #L128 was not covered by tests
}
return Collections.unmodifiableSet(this.managers);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
package eu.bbmri_eric.negotiator.database.model;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.*;
Copy link
Collaborator

@RadovanTomik RadovanTomik May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import jakarta.validation.constraints.NotNull;
import java.util.Objects;
import java.util.Set;
Expand Down
46 changes: 32 additions & 14 deletions src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
package eu.bbmri_eric.negotiator.database.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.NamedAttributeNode;
import jakarta.persistence.NamedEntityGraph;
import jakarta.persistence.OneToMany;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.persistence.*;
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved
import jakarta.validation.constraints.NotNull;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -78,6 +66,15 @@
@OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
private Set<Authority> authorities;

@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "network_person_link",
joinColumns = @JoinColumn(name = "network_id"),
inverseJoinColumns = @JoinColumn(name = "person_id"))
@Exclude
@Setter(AccessLevel.NONE)
private Set<Network> networks;

public void addResource(Resource resource) {
this.resources.add(resource);
resource.getRepresentatives().add(this);
Expand All @@ -95,6 +92,27 @@
resource.getRepresentatives().remove(this);
}

public void addNetwork(Network network) {
RadovanTomik marked this conversation as resolved.
Show resolved Hide resolved
this.networks.add(network);
if (!network.getManagers().contains(this)) {
network.addManager(this);

Check warning on line 98 in src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java#L98

Added line #L98 was not covered by tests
}
}

public Set<Network> getNetworks() {
if (Objects.isNull(this.networks)) {
return Set.of();

Check warning on line 104 in src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java#L104

Added line #L104 was not covered by tests
}
return Collections.unmodifiableSet(this.networks);
}

public void removeNetwork(Network network) {
this.networks.remove(network);

Check warning on line 110 in src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java#L110

Added line #L110 was not covered by tests
if (network.getManagers().contains(this)) {
network.removeManager(this);

Check warning on line 112 in src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java#L112

Added line #L112 was not covered by tests
}
}

Check warning on line 114 in src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Person.java#L114

Added line #L114 was not covered by tests

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator;
import jakarta.validation.constraints.NotNull;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.*;
import lombok.ToString.Exclude;

@ToString
Expand Down Expand Up @@ -71,6 +67,32 @@
@Exclude
private AccessForm accessForm;

@ManyToMany(mappedBy = "resources")
@Builder.Default
@Setter(AccessLevel.NONE)
private Set<Network> networks = new HashSet<>();

public void addNetwork(Network network) {
this.networks.add(network);
if (!network.getResources().contains(this)) {
network.addResource(this);

Check warning on line 78 in src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java#L78

Added line #L78 was not covered by tests
}
}

public Set<Network> getNetworks() {
if (Objects.isNull(this.networks)) {
return Set.of();

Check warning on line 84 in src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java#L84

Added line #L84 was not covered by tests
}
return Collections.unmodifiableSet(this.networks);
}

public void removeNetwork(Network network) {
this.networks.remove(network);
if (network.getResources().contains(this)) {
network.removeResource(this);

Check warning on line 92 in src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/eu/bbmri_eric/negotiator/database/model/Resource.java#L92

Added line #L92 was not covered by tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think it makes sense to have this API on both the Resource and the Network. Wouldn't it be better to just have it in one of them?

}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package eu.bbmri_eric.negotiator.database.repository;

import eu.bbmri_eric.negotiator.database.model.Network;
import jakarta.validation.constraints.NotNull;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NetworkRepository extends JpaRepository<Network, Long> {

Optional<Network> findByExternalId(String externalId);

boolean existsByExternalId(@NotNull String externalId);

boolean existsByUri(@NotNull String uri);
}
44 changes: 44 additions & 0 deletions src/main/resources/db/migration/postgresql/V6__Add_networks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
CREATE TABLE network
(
id BIGINT NOT NULL,
uri VARCHAR(255) NOT NULL,
name VARCHAR(255),
external_id VARCHAR(255) NOT NULL,
contact_email VARCHAR(255),
CONSTRAINT pk_network PRIMARY KEY (id)
);


ALTER TABLE network
ADD CONSTRAINT uc_network_externalid UNIQUE (external_id);

ALTER TABLE network
ADD CONSTRAINT uc_network_name UNIQUE (name);


CREATE TABLE network_resources_link
(
network_id BIGINT NOT NULL,
resource_id BIGINT NOT NULL,
CONSTRAINT pk_network_resources_link PRIMARY KEY (network_id, resource_id)
);

ALTER TABLE network_resources_link
ADD CONSTRAINT fk_netres_on_network FOREIGN KEY (network_id) REFERENCES network (id);

ALTER TABLE network_resources_link
ADD CONSTRAINT fk_netres_on_resource FOREIGN KEY (resource_id) REFERENCES resource (id);

CREATE TABLE network_person_link
(
network_id BIGINT NOT NULL,
person_id BIGINT NOT NULL,
CONSTRAINT pk_network_person_link PRIMARY KEY (network_id, person_id)
);

ALTER TABLE network_person_link
ADD CONSTRAINT fk_netper_on_network FOREIGN KEY (network_id) REFERENCES network (id);

ALTER TABLE network_person_link
ADD CONSTRAINT fk_netper_on_person FOREIGN KEY (person_id) REFERENCES person (id);

Loading
Loading