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

Feature/ForecastControllers #591

Merged
merged 10 commits into from
Apr 9, 2024
11 changes: 10 additions & 1 deletion cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,22 @@ public final class Controllers {
public static final String TIMESERIES = "timeseries";
public static final String LOCATIONS = "locations";

public static final String SPEC_ID = "spec-id";
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
public static final String LOCATION = "location";
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd go with "location-id", surprised there isn't an example already

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Collaborator

Choose a reason for hiding this comment

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

you can remove this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

public static final String SOURCE_ENTITY = "source-entity";
public static final String FORECAST_DATE_TIME = "forecast-date-time";
public static final String ISSUE_DATE_TIME = "issue-date-time";
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved

public static final String GROUP_ID = "group-id";
public static final String REPLACE_ASSIGNED_LOCS = "replace-assigned-locs";
public static final String REPLACE_ASSIGNED_TS = "replace-assigned-ts";
public static final String TS_IDS = "ts-ids";
public static final String DATE_FORMAT = "YYYY-MM-dd'T'hh:mm:ss[Z'['VV']']";
public static final String INCLUDE_ASSIGNED = "include-assigned";
public static final String ANY_MASK = "*";
public static final String ID_MASK = "id-mask";
public static final String OFFICE_MASK = "office-mask";
public static final String ID_MASK = "id-mask";
public static final String LOCATION_MASK = "location-mask";
public static final String NAME_MASK = "name-mask";
public static final String BOTTOM_MASK = "bottom-mask";
public static final String TOP_MASK = "top-mask";
Expand All @@ -154,6 +161,8 @@ public final class Controllers {
public static final String STANDARD_TEXT_ID = "standard-text-id";
public static final String TRIM = "trim";

public static final String FORECAST_SPEC = "forecast-spec";


static {
JavalinValidation.register(JooqDao.DeleteMethod.class, Controllers::getDeleteMethod);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package cwms.cda.api;

import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dto.forecast.ForecastInstance;
import cwms.cda.data.dto.forecast.ForecastSpec;
import cwms.cda.formatters.Formats;
import io.javalin.apibuilder.CrudHandler;
import io.javalin.http.Context;
import io.javalin.plugin.openapi.annotations.HttpMethod;
import io.javalin.plugin.openapi.annotations.OpenApi;
import io.javalin.plugin.openapi.annotations.OpenApiContent;
import io.javalin.plugin.openapi.annotations.OpenApiParam;
import io.javalin.plugin.openapi.annotations.OpenApiRequestBody;
import io.javalin.plugin.openapi.annotations.OpenApiResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import java.util.logging.Logger;

import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.FORECAST_DATE_TIME;
import static cwms.cda.api.Controllers.GET_ONE;
import static cwms.cda.api.Controllers.ID_MASK;
import static cwms.cda.api.Controllers.ISSUE_DATE_TIME;
import static cwms.cda.api.Controllers.LOCATION;
import static cwms.cda.api.Controllers.LOCATION_MASK;
import static cwms.cda.api.Controllers.NOT_SUPPORTED_YET;
import static cwms.cda.api.Controllers.OFFICE;
import static cwms.cda.api.Controllers.RESULTS;
import static cwms.cda.api.Controllers.SIZE;
import static cwms.cda.api.Controllers.SOURCE_ENTITY;
import static cwms.cda.api.Controllers.SPEC_ID;
import static cwms.cda.api.Controllers.STATUS_200;
import static cwms.cda.api.Controllers.STATUS_400;
import static cwms.cda.api.Controllers.STATUS_404;
import static cwms.cda.api.Controllers.STATUS_501;

public class ForecastInstanceController implements CrudHandler {
private static final Logger logger = Logger.getLogger(ForecastInstanceController.class.getName());

public static final String TAG = "Forecast";
private final MetricRegistry metrics;

private final Histogram requestResultSize;

public ForecastInstanceController(MetricRegistry metrics) {
this.metrics = metrics;
String className = this.getClass().getName();
requestResultSize = this.metrics.histogram((name(className, RESULTS, SIZE)));
}

private Timer.Context markAndTime(String subject) {
return Controllers.markAndTime(metrics, getClass().getName(), subject);
}

protected DSLContext getDslContext(Context ctx) {
return JooqDao.getDslContext(ctx);
}

@OpenApi(
description = "Used to create and save a forecast instance",
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = ForecastInstance.class, type = Formats.JSONV2)
},
required = true
),
method = HttpMethod.POST,
path = "/forecast-instance",
tags = TAG
)
@Override
public void create(@NotNull Context ctx) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
}

@OpenApi(
description = "Used to delete forecast instance data based on unique fields",
queryParams = {
@OpenApiParam(name = FORECAST_DATE_TIME, required = true, description = "Specifies the " +
dreina-gei marked this conversation as resolved.
Show resolved Hide resolved
"owning office of the forecast instance to be deleted."),
@OpenApiParam(name = ISSUE_DATE_TIME, required = true, description = "Specifies the " +
"owning office of the forecast instance to be deleted."),
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the " +
"owning office of the forecast spec associated with the forecast instance" +
"to be deleted."),
@OpenApiParam(name = SPEC_ID, required = true, description = "Specifies the " +
"spec id of the forecast spec associated with the forecast instance" +
"to be deleted."),
@OpenApiParam(name = LOCATION, required = true, description = "Specifies the " +
"location of the forecast spec associated with the forecast instance" +
"to be deleted."),
},
responses = {
@OpenApiResponse(status = STATUS_404, description = "The provided combination of "
+ "parameters did not find a forecast instance."),
},
path = "/forecast-instance",
method = HttpMethod.DELETE,
tags = TAG
)
@Override
public void delete(@NotNull Context ctx, @NotNull String forecastSpecId) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
}

@OpenApi(
description = "Used to get all forecast instances for a given forecast spec",
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the " +
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
"owning office of the forecast spec whose forecast instance is to be " +
"included in the response."),
@OpenApiParam(name = SPEC_ID, required = true, description = "Specifies the " +
"spec id of the forecast spec whose forecast instance data is to be " +
"included in the response."),
@OpenApiParam(name = LOCATION, required = true, description = "Specifies the " +
Copy link
Collaborator

Choose a reason for hiding this comment

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

@MikeNeilson what do you think about having a begin/end time window filter for the issue date?

"location of the forecast spec whose forecast instance data to be included " +
"in the response."),
},
responses = {
@OpenApiResponse(status = STATUS_200,
description = "A list of elements of the data set you've selected.",
content = {
@OpenApiContent(from = ForecastInstance.class, type = Formats.JSONV2)}),
@OpenApiResponse(status = STATUS_400, description = "Invalid parameter combination"),
@OpenApiResponse(status = STATUS_404, description = "The provided combination of "
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
+ "parameters did not find a forecast instance."),
@OpenApiResponse(status = STATUS_501, description = "Requested format is not "
+ "implemented")
},
path = "/forecast-instance/all",
method = HttpMethod.GET,
tags = TAG
)
@Override
public void getAll(@NotNull Context ctx) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
}

@OpenApi(
description = "Used to get all forecast instances for a given forecast spec",
queryParams = {
@OpenApiParam(name = FORECAST_DATE_TIME, required = true, description = "Specifies the " +
dreina-gei marked this conversation as resolved.
Show resolved Hide resolved
"forecast date time of the forecast instance to be retrieved."),
@OpenApiParam(name = ISSUE_DATE_TIME, required = true, description = "Specifies the " +
"issue date time of the forecast instance to be retrieved."),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the " +
"owning office of the forecast spec whose forecast instance is to be " +
"included in the response."),
@OpenApiParam(name = SPEC_ID, required = true, description = "Specifies the " +
"spec id of the forecast spec whose forecast instance data is to be " +
"included in the response."),
@OpenApiParam(name = LOCATION, required = true, description = "Specifies the " +
"location of the forecast spec whose forecast instance data to be included " +
"in the response."),
},
responses = {
@OpenApiResponse(status = STATUS_200,
description = "A list of elements of the data set you've selected.",
content = {
@OpenApiContent(from = ForecastInstance.class, type = Formats.JSONV2)}),
@OpenApiResponse(status = STATUS_400, description = "Invalid parameter combination"),
@OpenApiResponse(status = STATUS_404, description = "The provided combination of "
+ "parameters did not find a forecast instance."),
@OpenApiResponse(status = STATUS_501, description = "Requested format is not "
+ "implemented")
},
path = "/forecast-instance",
method = HttpMethod.GET,
tags = TAG
)
@Override
public void getOne(@NotNull Context ctx, @NotNull String id) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
}

@OpenApi(
description = "Update a forecast instance with provided values",
adamkorynta marked this conversation as resolved.
Show resolved Hide resolved
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = ForecastInstance.class, type = Formats.JSONV2)
},
required = true),
responses = {
@OpenApiResponse(status = STATUS_404, description = "Based on the combination of "
+ "inputs provided the location was not found.")
},
method = HttpMethod.PATCH,
path = "/forecast-instance",
tags = TAG
)
@Override
public void update(@NotNull Context ctx, @NotNull String id) {
try (final Timer.Context ignored = markAndTime(GET_ONE)) {
throw new UnsupportedOperationException(NOT_SUPPORTED_YET);
}
}

}
Loading