Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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 @@ -154,9 +154,7 @@ public void getOne(Context ctx, @NotNull String categoryId) {
logger.atInfo().log("%s%nfor request %s", re, ctx.fullUrl());
ctx.status(HttpServletResponse.SC_NOT_FOUND).json(re);
}

}

}

@OpenApi(
Expand All @@ -169,6 +167,8 @@ public void getOne(Context ctx, @NotNull String categoryId) {
queryParams = {
@OpenApiParam(name = FAIL_IF_EXISTS, type = Boolean.class,
description = "Create will fail if provided ID already exists. Default: true"),
@OpenApiParam(name = IGNORE_NULLS, type = Boolean.class,
description = "Ignore null values in the request body. Default: true")
},
method = HttpMethod.POST,
tags = {TAG}
Expand All @@ -184,16 +184,45 @@ public void create(Context ctx) {
ContentType contentType = Formats.parseHeader(formatHeader, TimeSeriesCategory.class);
TimeSeriesCategory deserialize = Formats.parseContent(contentType, body, TimeSeriesCategory.class);
boolean failIfExists = ctx.queryParamAsClass(FAIL_IF_EXISTS, Boolean.class).getOrDefault(true);
boolean ignoreNulls = ctx.queryParamAsClass(IGNORE_NULLS, Boolean.class).getOrDefault(true);
TimeSeriesCategoryDao dao = new TimeSeriesCategoryDao(dsl);
dao.create(deserialize, failIfExists);
dao.create(deserialize, failIfExists, ignoreNulls);
ctx.status(HttpServletResponse.SC_CREATED);
}
}

@OpenApi(ignore = true)
@OpenApi(
description = "Update existing TimeSeriesCategory. Allows for renaming of the category.",
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(from = TimeSeriesCategory.class, type = Formats.JSON)
},
required = true),
pathParams = {
@OpenApiParam(name = CATEGORY_ID, required = true, description = "Specifies "
+ "the original timeseries category to rename."),
@OpenApiParam(name = IGNORE_NULLS, type = Boolean.class,
description = "Ignore null values in the request body. Default: true")
},
method = HttpMethod.PATCH,
tags = {TAG}
)
@Override
public void update(@NotNull Context ctx, @NotNull String locationCode) {
ctx.status(HttpServletResponse.SC_NOT_IMPLEMENTED).json(CdaError.notImplemented());
public void update(@NotNull Context ctx, @NotNull String categoryId) {
try (Timer.Context ignored = markAndTime(UPDATE)) {
DSLContext dsl = getDslContext(ctx);

String formatHeader = ctx.req.getContentType();
String body = ctx.body();

boolean ignoreNulls = ctx.queryParamAsClass(IGNORE_NULLS, Boolean.class).getOrDefault(true);
ContentType contentType = Formats.parseHeader(formatHeader, TimeSeriesCategory.class);
TimeSeriesCategory deserialize = Formats.parseContent(contentType, body, TimeSeriesCategory.class);

TimeSeriesCategoryDao dao = new TimeSeriesCategoryDao(dsl);
dao.update(categoryId, deserialize, ignoreNulls );
ctx.status(HttpServletResponse.SC_OK);
}
}

@OpenApi(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package cwms.cda.api;

import static com.codahale.metrics.MetricRegistry.name;
import static cwms.cda.api.Controllers.CASCADE_DELETE;
import static cwms.cda.api.Controllers.CATEGORY_ID;
import static cwms.cda.api.Controllers.CATEGORY_OFFICE_ID;
import static cwms.cda.api.Controllers.CREATE;
Expand Down Expand Up @@ -197,22 +198,8 @@ public void getOne(@NotNull Context ctx, @NotNull String groupId) {
String formatHeader = ctx.header(Header.ACCEPT);
ContentType contentType = Formats.parseHeader(formatHeader, TimeSeriesGroup.class);

TimeSeriesGroup group = null;
List<TimeSeriesGroup> timeSeriesGroups = dao.getTimeSeriesGroups(tsOffice, groupOffice, categoryOffice,
categoryId, groupId);
if (timeSeriesGroups != null && !timeSeriesGroups.isEmpty()) {
if (timeSeriesGroups.size() == 1) {
group = timeSeriesGroups.get(0);
} else {
// An error. [office, categoryId, groupId] should have, at most, one match
String message = String.format(
"Multiple TimeSeriesGroups returned from getTimeSeriesGroups "
+ "for:%s category:%s groupId:%s At most one match was "
+ "expected. Found:%s",
groupOffice, categoryId, groupId, timeSeriesGroups);
throw new IllegalArgumentException(message);
}
}
TimeSeriesGroup group = dao.getTimeSeriesGroup(tsOffice, groupOffice, categoryOffice, categoryId, groupId);

if (group != null) {
String result = Formats.format(contentType, group);

Expand Down Expand Up @@ -327,6 +314,8 @@ public void update(@NotNull Context ctx, @NotNull String oldGroupId) {
+ "time series category of the time series group to be deleted"),
@OpenApiParam(name = OFFICE, required = true, description = "Specifies the "
+ "owning office of the time series group to be deleted"),
@OpenApiParam(name = CASCADE_DELETE, type = Boolean.class,
description = "Specifies whether to unassign time series in this group before deleting. Default: false"),
},
method = HttpMethod.DELETE,
tags = {TAG}
Expand All @@ -337,9 +326,10 @@ public void delete(@NotNull Context ctx, @NotNull String groupId) {
DSLContext dsl = getDslContext(ctx);

TimeSeriesGroupDao dao = new TimeSeriesGroupDao(dsl);
boolean cascadeDelete = ctx.queryParamAsClass(CASCADE_DELETE, Boolean.class).getOrDefault(false);
String office = ctx.queryParam(OFFICE);
String categoryId = ctx.queryParam(CATEGORY_ID);
dao.delete(categoryId, groupId, office);
dao.delete(categoryId, groupId, office, cascadeDelete);
ctx.status(HttpServletResponse.SC_NO_CONTENT);
}
}
Expand Down
2 changes: 1 addition & 1 deletion cwms-data-api/src/main/java/cwms/cda/data/dao/Dao.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.google.common.flogger.FluentLogger;
import cwms.cda.data.dto.CwmsDTO;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.jooq.DSLContext;
Expand All @@ -43,6 +42,7 @@ public abstract class Dao<T> {
public static final int CWMS_18_1_8 = 180108;
public static final int CWMS_21_1_1 = 210101;
public static final int CWMS_23_03_16 = 230316;
public static final int CWMS_25_07_01 = 250701;

public static final String PROP_BASE = "cwms.cda.data.dao.dao";
public static final String VERSION_NAME = "version";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@
import cwms.cda.data.dto.TimeSeriesCategory;
import java.util.List;
import java.util.Optional;
import org.jooq.DSLContext;
import org.jooq.Record3;
import org.jooq.Select;
import org.jooq.SelectWhereStep;

import cwms.cda.data.dto.TimeSeriesGroup;
import org.jooq.*;
import usace.cwms.db.jooq.codegen.packages.CWMS_TS_PACKAGE;
import usace.cwms.db.jooq.codegen.tables.AV_TS_CAT_GRP;

Expand Down Expand Up @@ -76,23 +75,62 @@ public List<TimeSeriesCategory> getTimeSeriesCategories() {
}

public void delete(String categoryId, boolean cascadeDelete, String office) {

if(cascadeDelete){
cascadeDelete(categoryId, office);
} else {
connection(dsl, conn -> {
DSLContext dslContext = getDslContext(conn, office);
CWMS_TS_PACKAGE.call_DELETE_TS_CATEGORY(dslContext.configuration(), categoryId, formatBool(false), office);
});
}
}

private void cascadeDelete(String categoryId, String office) {
connection(dsl, conn -> {
DSLContext dslContext = getDslContext(conn, office);
CWMS_TS_PACKAGE.call_DELETE_TS_CATEGORY(
dslContext.configuration(), categoryId,
formatBool(cascadeDelete), office);
});

if (getDbVersion() > Dao.CWMS_25_07_01) {
// With newer schema it should just work, don't need transaction
Configuration config = dslContext.configuration();
CWMS_TS_PACKAGE.call_DELETE_TS_CATEGORY(config, categoryId, formatBool(true), office);
} else {
// Before 2/3/2026 DELETE_TS_CATEGORY wasn't removing assignments from groups so we start a transaction and do the deletes

dslContext.transaction((Configuration trx) -> {
Configuration config = trx.dsl().configuration();

TimeSeriesGroupDao dao = new TimeSeriesGroupDao(dslContext);
List<TimeSeriesGroup> timeSeriesGroups = dao.getTimeSeriesGroups(null, null, office, false, categoryId, null);
for (TimeSeriesGroup group : timeSeriesGroups) {
dao.delete(categoryId, group.getId(), office, true);
}

// Before 2/3/2026 DELETE_TS_CATEGORY wasn't removing assignments from groups
CWMS_TS_PACKAGE.call_DELETE_TS_CATEGORY(config, categoryId, formatBool(true), office);
});
}

});
}

public void create(TimeSeriesCategory category, boolean failIfExists) {
public void create(TimeSeriesCategory category, boolean failIfExists, boolean ignoreNulls) {
String office = category.getOfficeId();

connection(dsl, conn -> {
DSLContext dslContext = getDslContext(conn, office);
CWMS_TS_PACKAGE.call_STORE_TS_CATEGORY(
dslContext.configuration(), category.getId(), category.getDescription(),
formatBool(failIfExists), "T", office);
dslContext.configuration(), category.getId(), category.getDescription(),
formatBool(failIfExists), formatBool(ignoreNulls), office);
});
}

public void update(String oldCategoryId, TimeSeriesCategory category, boolean ignoreNulls) {
String office = category.getOfficeId();
connection(dsl, conn -> {
DSLContext dslContext = getDslContext(conn, office);
CWMS_TS_PACKAGE.call_RENAME_TS_CATEGORY(dslContext.configuration(), oldCategoryId, category.getId(), office);
CWMS_TS_PACKAGE.call_STORE_TS_CATEGORY(dslContext.configuration(), category.getId(), category.getDescription(), "F", formatBool(ignoreNulls), office);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ public List<TimeSeriesGroup> getTimeSeriesGroups(String tsOfficeId, String group

}

public TimeSeriesGroup getTimeSeriesGroup(String tsOfficeId, String groupOfficeId, String categoryOfficeId,
String categoryId, String groupId) {
List<TimeSeriesGroup> timeSeriesGroups = getTimeSeriesGroups(tsOfficeId, groupOfficeId, categoryOfficeId, categoryId, groupId);
if(timeSeriesGroups != null && !timeSeriesGroups.isEmpty()){
if(timeSeriesGroups.size() == 1){
return timeSeriesGroups.get(0);
} else {
throw new IllegalArgumentException("Multiple TimeSeriesGroups returned from getTimeSeriesGroups " +
"for office:" + tsOfficeId + " category:" + categoryId + " group:" + groupId + " At most one match was " +
"expected.");
}
}
return null;
}

public List<TimeSeriesGroup> getTimeSeriesGroups(String tsOfficeId, String groupOfficeId, String categoryOfficeId,
String categoryId, String groupId) {
Expand Down Expand Up @@ -249,13 +263,35 @@ private Condition buildWhereCondition(String categoryId, String groupId) {
return whereCondition;
}

public void delete(String categoryId, String groupId, String office, boolean cascade) {

boolean databaseHasCascadeFlag = getDbVersion() > Dao.CWMS_25_07_01;

connection(dsl, conn -> {
if (databaseHasCascadeFlag) {
/* Normally we'd just call via jooq's CWMS_TS_PACKAGE.call_DELETE_TS_GROUP but the
* version that takes "cascade" is new and not in the codegen.
*/
DSLContext dslContext = getDslContext(conn, office);
dslContext.query("begin cwms_ts.delete_ts_group(p_category_id => ?, p_group_id => ?, p_cascade => ?, p_office_id => ?); end;", categoryId, groupId, formatBool(cascade), office).execute();
} else {
DSLContext dslContext = getDslContext(conn, office);
dslContext.transaction((Configuration trx) -> {
Configuration config = trx.dsl().configuration();
if (cascade) {
TimeSeriesGroup group = getTimeSeriesGroup(null, office, null, categoryId, groupId);
if (group != null) {
unassignAllTs(group, office);
}
}
CWMS_TS_PACKAGE.call_DELETE_TS_GROUP(config, categoryId, groupId, office);
});
}
});
}

public void delete(String categoryId, String groupId, String office) {
connection(dsl, c ->
CWMS_TS_PACKAGE.call_DELETE_TS_GROUP(
getDslContext(c,office).configuration(), categoryId, groupId, office
)
);
delete(categoryId, groupId, office, false);
}

public void create(TimeSeriesGroup group, boolean failIfExists) {
Expand Down
Loading
Loading