com.zuunr.restbed.repository.sqlserver.impl.UpdateItem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of restbed-repository-sqlserver Show documentation
Show all versions of restbed-repository-sqlserver Show documentation
SQL Server implementation of the reactive repository interface in core project
/*
* Copyright 2018 Zuunr AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.zuunr.restbed.repository.sqlserver.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Component;
import com.zuunr.json.JsonObject;
import com.zuunr.json.JsonObjectSupport;
import com.zuunr.restbed.core.exchange.ErrorBody;
import com.zuunr.restbed.core.exchange.Exchange;
import com.zuunr.restbed.core.exchange.Method;
import com.zuunr.restbed.core.exchange.Request;
import com.zuunr.restbed.core.exchange.Response;
import com.zuunr.restbed.core.exchange.StatusCode;
import com.zuunr.restbed.repository.ReactiveRepository;
import com.zuunr.restbed.repository.sqlserver.impl.model.NoResource;
import com.zuunr.restbed.repository.sqlserver.util.CollectionNameProvider;
import com.zuunr.restbed.repository.sqlserver.util.EtagProvider;
import com.zuunr.restbed.repository.sqlserver.util.ResourceDeserializer;
import com.zuunr.restbed.repository.sqlserver.util.SchemaNameProvider;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
/**
* Primary updateItem implementation of {@link ReactiveRepository}.
*
* @see ReactiveRepository
*/
@Component
public class UpdateItem {
private final Logger logger = LoggerFactory.getLogger(UpdateItem.class);
private static final String CONFLICT_ERROR_MESSAGE = "Simultaneous update";
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private EtagProvider etagProvider;
private CollectionNameProvider collectionNameProvider;
private SchemaNameProvider schemaNameProvider;
private GetItem getItem;
private ResourceDeserializer resourceDeserializer;
@Autowired
public UpdateItem(
NamedParameterJdbcTemplate namedParameterJdbcTemplate,
EtagProvider etagProvider,
CollectionNameProvider collectionNameProvider,
SchemaNameProvider schemaNameProvider,
GetItem getItem,
ResourceDeserializer resourceDeserializer) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
this.etagProvider = etagProvider;
this.collectionNameProvider = collectionNameProvider;
this.schemaNameProvider = schemaNameProvider;
this.getItem = getItem;
this.resourceDeserializer = resourceDeserializer;
}
/**
* @see ReactiveRepository#updateItem(Mono, Class)
*/
public Mono> updateItem(Exchange exchange, Class resourceClass) {
String collectionName = collectionNameProvider.getCollectionName(exchange.getRequest());
String schemaName = schemaNameProvider.getSchemaName();
String id = exchange.getRequest().getApiUriInfo().itemId();
JsonObject body = exchange.getRequest().getBodyAsJsonObject();
String etag = etagProvider.getEtag(body);
JsonObject bodyWithNewEtag = etagProvider.appendEtag(body);
StringBuilder sql = new StringBuilder()
.append("UPDATE " + schemaName + "." + collectionName)
.append(" SET document = :document")
.append(" WHERE JSON_VALUE(document, '$.id') = :id")
.append(" AND JSON_VALUE(document, '$.meta.etag') = :etag");
MapSqlParameterSource parameters = new MapSqlParameterSource()
.addValue("id", id)
.addValue("etag", etag)
.addValue("document", bodyWithNewEtag.asJson());
return Mono.fromCallable(() -> updateDocument(sql.toString(), parameters))
.subscribeOn(Schedulers.elastic())
.flatMap(o -> successUpdate(exchange, bodyWithNewEtag, o, resourceClass));
}
private int updateDocument(String sql, MapSqlParameterSource parameters) {
return namedParameterJdbcTemplate.update(sql, parameters);
}
private Mono> successUpdate(Exchange exchange, JsonObject savedDocument, Integer updatedRows, Class resourceClass) {
if (updatedRows == 0) {
return checkIfExistsAndReturnResponse(exchange);
}
if (logger.isDebugEnabled()) {
logger.debug("Successfully updated item: {}", exchange.getRequest().getUrl());
}
T body = resourceDeserializer.deserializeJsonObject(savedDocument, resourceClass);
return Mono.just(exchange
.response(Response.create(StatusCode._200_OK)
.body(body)));
}
private Mono> checkIfExistsAndReturnResponse(Exchange exchange) {
Exchange fetchExchange = Exchange.empty()
.request(Request.create(Method.GET)
.url(exchange.getRequest().getUrl()));
return getItem.getItem(fetchExchange, NoResource.class)
.map(o -> returnStatusCode(exchange, o));
}
private Exchange returnStatusCode(Exchange originalExchange, Exchange fetchExchange) {
Response response = null;
if (fetchExchange.getResponse().getStatusCode() == StatusCode._200_OK.getCode()) {
response = Response.create(StatusCode._409_CONFLICT)
.errorBody(ErrorBody.of(JsonObject.EMPTY.put("error", CONFLICT_ERROR_MESSAGE)));
} else {
response = Response.create(StatusCode._404_NOT_FOUND);
}
if (logger.isDebugEnabled()) {
logger.debug("Failed to update item, returning with status code: {}", response.getStatusCode());
}
return originalExchange.response(response);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy