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

CTO-118 Updated Gate Change Controller and DAO #904

Merged
merged 2 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@

package cwms.cda.api.location.kind;

import static cwms.cda.api.Controllers.CREATE;
import static cwms.cda.api.Controllers.FAIL_IF_EXISTS;
import static cwms.cda.api.Controllers.STATUS_201;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.api.BaseHandler;
Expand All @@ -40,7 +44,7 @@
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import static cwms.cda.api.Controllers.*;


public class GateChangeCreateController extends BaseHandler {

Expand All @@ -49,22 +53,22 @@ public GateChangeCreateController(MetricRegistry metrics) {
}

@OpenApi(
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = GateChange.class, isArray = true, type = Formats.JSONV1),
@OpenApiContent(from = GateChange.class, isArray = true, type = Formats.JSON)
},
required = true),
queryParams = {
@OpenApiParam(name = FAIL_IF_EXISTS, type = Boolean.class,
description = "Create will fail if provided Gate Changes already exist. Default: true")
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = GateChange.class, isArray = true, type = Formats.JSONV1),
@OpenApiContent(from = GateChange.class, isArray = true, type = Formats.JSON)
},
description = "Create CWMS Gate Changes",
method = HttpMethod.POST,
tags = {OutletController.TAG},
responses = {
@OpenApiResponse(status = STATUS_201, description = "Gate Changes successfully stored to CWMS.")
}
required = true),
queryParams = {
@OpenApiParam(name = FAIL_IF_EXISTS, type = Boolean.class,
description = "Create will fail if provided Gate Changes already exist. Default: true")
},
description = "Create CWMS Gate Changes",
method = HttpMethod.POST,
tags = {OutletController.TAG},
responses = {
@OpenApiResponse(status = STATUS_201, description = "Gate Changes successfully stored to CWMS.")
}
)
@Override
public void handle(@NotNull Context context) throws Exception {
Expand All @@ -73,6 +77,9 @@ public void handle(@NotNull Context context) throws Exception {
ContentType contentType = Formats.parseHeader(formatHeader, GateChange.class);
List<GateChange> changes = Formats.parseContentList(contentType, context.body(), GateChange.class);

// Sort changes by date to avoid DB errors
changes.sort(GateChange::compareTo);

try (Timer.Context ignored = markAndTime(CREATE)) {
DSLContext dsl = JooqDao.getDslContext(context);
OutletDao dao = new OutletDao(dsl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,30 @@

package cwms.cda.api.location.kind;

import com.codahale.metrics.Histogram;
import static cwms.cda.api.Controllers.CREATE;
import static cwms.cda.api.Controllers.DELETE;
import static cwms.cda.api.Controllers.FAIL_IF_EXISTS;
import static cwms.cda.api.Controllers.GET_ALL;
import static cwms.cda.api.Controllers.GET_ONE;
import static cwms.cda.api.Controllers.METHOD;
import static cwms.cda.api.Controllers.NAME;
import static cwms.cda.api.Controllers.OFFICE;
import static cwms.cda.api.Controllers.PROJECT_ID;
import static cwms.cda.api.Controllers.STATUS_200;
import static cwms.cda.api.Controllers.STATUS_204;
import static cwms.cda.api.Controllers.STATUS_404;
import static cwms.cda.api.Controllers.queryParamAsClass;
import static cwms.cda.api.Controllers.requiredParam;
import static cwms.cda.data.dao.JooqDao.getDslContext;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import cwms.cda.api.BaseCrudHandler;
import cwms.cda.api.Controllers;
import cwms.cda.data.dao.JooqDao;
import cwms.cda.data.dao.location.kind.OutletDao;
import cwms.cda.data.dto.location.kind.Outlet;
import cwms.cda.formatters.ContentType;
import cwms.cda.formatters.Formats;
import io.javalin.apibuilder.CrudHandler;
import io.javalin.core.util.Header;
import io.javalin.http.Context;
import io.javalin.plugin.openapi.annotations.HttpMethod;
Expand All @@ -43,9 +56,7 @@
import javax.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.jooq.DSLContext;
import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.*;
import static cwms.cda.data.dao.JooqDao.getDslContext;


public class OutletController extends BaseCrudHandler {
static final String TAG = "Outlets";
Expand All @@ -55,22 +66,22 @@ public OutletController(MetricRegistry metrics) {
}

@OpenApi(
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Outlet.class, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, type = Formats.JSON)
},
required = true),
queryParams = {
@OpenApiParam(name = FAIL_IF_EXISTS, type = Boolean.class,
description = "Create will fail if provided ID already exists. Default: true")
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = Outlet.class, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, type = Formats.JSON)
},
description = "Create CWMS Outlet",
method = HttpMethod.POST,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "Outlet successfully stored to CWMS.")
}
required = true),
queryParams = {
@OpenApiParam(name = FAIL_IF_EXISTS, type = Boolean.class,
description = "Create will fail if provided ID already exists. Default: true")
},
description = "Create CWMS Outlet",
method = HttpMethod.POST,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "Outlet successfully stored to CWMS.")
}
)
@Override
public void create(@NotNull Context ctx) {
Expand All @@ -88,20 +99,20 @@ public void create(@NotNull Context ctx) {
}

@OpenApi(
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Office id for the reservoir project location " +
"associated with the outlets."),
@OpenApiParam(name = PROJECT_ID, required = true, description = "Specifies the project-id of the " +
"Outlets whose data is to be included in the response."),
},
responses = {
@OpenApiResponse(status = STATUS_200, content = {
@OpenApiContent(from = Outlet.class, isArray = true, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, isArray = true, type = Formats.JSON)
})
},
description = "Returns matching CWMS Outlet Data for a Reservoir Project.",
tags = {TAG}
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Office id for the reservoir project location "
+ "associated with the outlets."),
@OpenApiParam(name = PROJECT_ID, required = true, description = "Specifies the project-id of the "
+ "Outlets whose data is to be included in the response."),
},
responses = {
@OpenApiResponse(status = STATUS_200, content = {
@OpenApiContent(from = Outlet.class, isArray = true, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, isArray = true, type = Formats.JSON)
})
},
description = "Returns matching CWMS Outlet Data for a Reservoir Project.",
tags = {TAG}
)
@Override
public void getAll(@NotNull Context ctx) {
Expand All @@ -122,23 +133,23 @@ public void getAll(@NotNull Context ctx) {
}

@OpenApi(
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of the " +
"Outlet to be created."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be retrieved."),
},
responses = {
@OpenApiResponse(status = STATUS_200,
content = {
@OpenApiContent(from = Outlet.class, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, type = Formats.JSON)
})
},
description = "Returns CWMS Outlet Data",
tags = {TAG}
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of the "
+ "Outlet to be created."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be retrieved."),
},
responses = {
@OpenApiResponse(status = STATUS_200,
content = {
@OpenApiContent(from = Outlet.class, type = Formats.JSONV1),
@OpenApiContent(from = Outlet.class, type = Formats.JSON)
})
},
description = "Returns CWMS Outlet Data",
tags = {TAG}
)
@Override
public void getOne(@NotNull Context ctx, @NotNull String name) {
Expand All @@ -158,21 +169,21 @@ public void getOne(@NotNull Context ctx, @NotNull String name) {
}

@OpenApi(
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of "
+ "the outlet to be renamed."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be renamed."),
@OpenApiParam(name = NAME, required = true, description = "Specifies the new outlet location-id."),
},
description = "Rename CWMS Outlet",
method = HttpMethod.PATCH,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "CWMS Outlet successfully renamed.")
}
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of "
+ "the outlet to be renamed."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be renamed."),
@OpenApiParam(name = NAME, required = true, description = "Specifies the new outlet location-id."),
},
description = "Rename CWMS Outlet",
method = HttpMethod.PATCH,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "CWMS Outlet successfully renamed.")
}
)
@Override
public void update(@NotNull Context ctx, @NotNull String name) {
Expand All @@ -187,25 +198,24 @@ public void update(@NotNull Context ctx, @NotNull String name) {
}

@OpenApi(
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of the outlet to be" +
" deleted."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be deleted."),
@OpenApiParam(name = METHOD, description = "Specifies the delete method used. " +
"Defaults to \"DELETE_KEY\"",
type = JooqDao.DeleteMethod.class)
},
description = "Delete CWMS Outlet",
method = HttpMethod.DELETE,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "Outlet successfully deleted from CWMS."),
@OpenApiResponse(status = STATUS_404, description = "Based on the combination of "
+ "inputs provided the outlet was not found.")
}
pathParams = {
@OpenApiParam(name = NAME, required = true, description = "Specifies the location-id of the outlet to be"
+ " deleted."),
},
queryParams = {
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the owning office of "
+ "the outlet to be deleted."),
@OpenApiParam(name = METHOD, description = "Specifies the delete method used. "
+ "Defaults to \"DELETE_KEY\"", type = JooqDao.DeleteMethod.class)
},
description = "Delete CWMS Outlet",
method = HttpMethod.DELETE,
tags = {TAG},
responses = {
@OpenApiResponse(status = STATUS_204, description = "Outlet successfully deleted from CWMS."),
@OpenApiResponse(status = STATUS_404, description = "Based on the combination of "
+ "inputs provided the outlet was not found.")
}
)
@Override
public void delete(@NotNull Context ctx, @NotNull String name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

package cwms.cda.data.dao.location.kind;

import static cwms.cda.data.dao.location.kind.LocationUtil.getLocationRef;

import cwms.cda.api.enums.UnitSystem;
import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dao.DeleteRule;
Expand All @@ -45,6 +47,7 @@
import java.util.stream.Collectors;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.exception.IntegrityConstraintViolationException;
import org.jooq.impl.DSL;
import usace.cwms.db.jooq.codegen.packages.CWMS_OUTLET_PACKAGE;
import usace.cwms.db.jooq.codegen.udt.records.GATE_CHANGE_OBJ_T;
Expand All @@ -55,7 +58,7 @@
import usace.cwms.db.jooq.codegen.udt.records.PROJECT_STRUCTURE_OBJ_T;
import usace.cwms.db.jooq.codegen.udt.records.STR_TAB_T;
import usace.cwms.db.jooq.codegen.udt.records.STR_TAB_TAB_T;
import static cwms.cda.data.dao.location.kind.LocationUtil.getLocationRef;


public class OutletDao extends JooqDao<Outlet> {

Expand Down Expand Up @@ -114,8 +117,12 @@ public void storeOutlet(Outlet outlet, boolean failIfExists) {
public void deleteOutlet(String officeId, String locationId, DeleteRule deleteRule) {
connection(dsl, conn -> {
setOffice(conn, officeId);
CWMS_OUTLET_PACKAGE.call_DELETE_OUTLET(DSL.using(conn).configuration(), locationId, deleteRule.getRule(),
officeId);
try {
CWMS_OUTLET_PACKAGE.call_DELETE_OUTLET(DSL.using(conn).configuration(), locationId,
deleteRule.getRule(), officeId);
} catch (IntegrityConstraintViolationException e) {
throw new NotFoundException(e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Not found doesn't make sense given the parent exception. 409 Conflict https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/409 makes more sense.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Swapped for a DeleteConflictException. The error code received by HCDA isn't the most useful, ("Data already exists for this request"). Maybe there's another exception that will provide more detail?

Copy link
Contributor

Choose a reason for hiding this comment

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

It should send basically what the constraint is "something depends on it." We'll have to look into that later.

}
});
}

Expand Down Expand Up @@ -257,8 +264,8 @@ public void renameOutlet(String officeId, String oldOutletId, String newOutletId
}

public List<GateChange> retrieveOperationalChanges(CwmsId projectId, Instant startTime, Instant endTime,
boolean startInclusive, boolean endInclusive, UnitSystem unitSystem,
long rowLimit) {
boolean startInclusive, boolean endInclusive,
UnitSystem unitSystem, long rowLimit) {
return connectionResult(dsl, conn -> {
setOffice(conn, projectId.getOfficeId());

Expand All @@ -267,11 +274,12 @@ public List<GateChange> retrieveOperationalChanges(CwmsId projectId, Instant sta
Timestamp endTimestamp = Timestamp.from(endTime);
BigInteger rowLimitBig = BigInteger.valueOf(rowLimit);
GATE_CHANGE_TAB_T changeTab = CWMS_OUTLET_PACKAGE.call_RETRIEVE_GATE_CHANGES(
DSL.using(conn).configuration(), locationRef, startTimestamp, endTimestamp, "UTC", unitSystem.getValue(),
formatBool(startInclusive), formatBool(endInclusive), rowLimitBig);
DSL.using(conn).configuration(), locationRef, startTimestamp, endTimestamp, "UTC",
unitSystem.getValue(), formatBool(startInclusive), formatBool(endInclusive), rowLimitBig);

if (changeTab == null) {
throw new NotFoundException("No changes found for " + projectId.getOfficeId() + "." + projectId.getName()
throw new NotFoundException("No changes found for " + projectId.getOfficeId() + "."
+ projectId.getName()
+ "\nStart time: " + startTime
+ "\nEnd time: " + endTime
+ "\nStart inclusive: " + startInclusive
Expand Down
Loading
Loading