-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #100 from qbicsoftware/development
Add migration endpoint to migrate data (#99)
- Loading branch information
Showing
4 changed files
with
145 additions
and
9 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
src/main/groovy/life/qbic/controller/DatabaseMigrationController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package life.qbic.controller; | ||
|
||
import io.micronaut.context.annotation.Requires; | ||
import io.micronaut.http.MediaType; | ||
import io.micronaut.http.annotation.Controller; | ||
import io.micronaut.http.annotation.Get; | ||
import io.micronaut.http.annotation.PathVariable; | ||
import io.micronaut.security.annotation.Secured; | ||
import io.micronaut.security.rules.SecurityRule; | ||
import java.time.Instant; | ||
import javax.annotation.security.RolesAllowed; | ||
import javax.inject.Inject; | ||
import life.qbic.auth.Authentication; | ||
import life.qbic.db.tools.Migrator; | ||
|
||
/** | ||
* Utility tool to migrate data. | ||
* | ||
* @since 2.0.0 | ||
*/ | ||
@Requires(beans = Authentication.class) | ||
@Secured(SecurityRule.IS_AUTHENTICATED) | ||
@Controller("/v2/migrate") | ||
public class DatabaseMigrationController { | ||
|
||
private final Migrator migrator; | ||
|
||
@Inject | ||
public DatabaseMigrationController(Migrator migrator) { | ||
this.migrator = migrator; | ||
} | ||
|
||
@Get(produces = MediaType.APPLICATION_JSON) | ||
@RolesAllowed("WRITER") | ||
void migrateAllData() { | ||
migrator.migrateFromVersionOneToVersionTwo(); | ||
} | ||
|
||
@Get(uri = "/{utcDateTime}", produces = MediaType.APPLICATION_JSON) | ||
@RolesAllowed("WRITER") | ||
void migrateAllData(@PathVariable String utcDateTime) { | ||
Instant earliestTime = Instant.parse(utcDateTime); | ||
migrator.migrateFromVersionOneToVersionTwo(earliestTime); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package life.qbic.db.tools | ||
|
||
import groovy.sql.Sql | ||
import life.qbic.api.rest.v2.samples.SampleStatusDto | ||
import life.qbic.api.rest.v2.samples.SamplesControllerV2 | ||
import life.qbic.api.rest.v2.samples.StatusChangeRequest | ||
|
||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
import javax.sql.DataSource | ||
import java.sql.Timestamp | ||
import java.time.Instant | ||
|
||
import static java.util.Objects.requireNonNull | ||
|
||
@Singleton | ||
class Migrator { | ||
|
||
private final DbInteractor dbInteractor | ||
private final SamplesControllerV2 controllerV2 | ||
|
||
@Inject | ||
Migrator(DbInteractor dbInteractor, SamplesControllerV2 controllerV2) { | ||
this.dbInteractor = dbInteractor | ||
this.controllerV2 = controllerV2 | ||
} | ||
|
||
/** | ||
* migrates data from the old data schema to the schema of v2. Starts at the earliestModification. | ||
* @param earliestModification | ||
*/ | ||
void migrateFromVersionOneToVersionTwo(Instant earliestModification) { | ||
dbInteractor.statusChangeRequests(earliestModification).forEach(it -> controllerV2.moveSampleToStatus(it.sampleCode, new StatusChangeRequest(it.statusDto, it.arrivalTime.toString()))) | ||
} | ||
|
||
/** | ||
* migrates data from the old data schema to the schema of v2. | ||
*/ | ||
void migrateFromVersionOneToVersionTwo() { | ||
dbInteractor.statusChangeRequests(new Date(0).toInstant()).forEach(it -> controllerV2.moveSampleToStatus(it.sampleCode, new StatusChangeRequest(it.statusDto, it.arrivalTime.toString()))) | ||
} | ||
|
||
static class StatusChange { | ||
final String sampleCode | ||
final SampleStatusDto statusDto | ||
final Instant arrivalTime | ||
|
||
StatusChange(String sampleCode, SampleStatusDto statusDto, Instant arrivalTime) { | ||
this.sampleCode = sampleCode | ||
this.statusDto = statusDto | ||
this.arrivalTime = arrivalTime | ||
} | ||
} | ||
|
||
@Singleton | ||
static class DbInteractor { | ||
|
||
private final DataSource dataSource | ||
|
||
@Inject | ||
DbInteractor(DataSource dataSource) { | ||
this.dataSource = dataSource | ||
} | ||
|
||
List<StatusChange> statusChangeRequests(Instant earliestModification) { | ||
def connection = requireNonNull(dataSource.getConnection()) | ||
String query = "SELECT sample_id, sample_status, arrival_time FROM samples_locations WHERE arrival_time >= :earliestModification ORDER BY arrival_time" | ||
try (Sql sql = new Sql(connection)) { | ||
def rows = sql.rows(query, [earliestModification: Timestamp.from(earliestModification)]) | ||
return rows.stream() | ||
.map(it -> new StatusChange( | ||
it.get("sample_id") as String, | ||
SampleStatusDto.valueOf(it.get("sample_status") as String), | ||
(it.get("arrival_time") as Timestamp).toInstant())) | ||
.sorted((it1, it2) -> it1.arrivalTime.compareTo(it2.arrivalTime)) | ||
.collect() | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters