All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zuunr.restbed.repository.sqlserver.impl.UpdateItem Maven / Gradle / Ivy

There is a newer version: 1.0.0.M7-59f711a
Show newest version
/*
 * 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