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

com.yourrents.services.geodata.repository.CountryRepository Maven / Gradle / Ivy

The newest version!
package com.yourrents.services.geodata.repository;

/*-
 * #%L
 * YourRents GeoData Service
 * %%
 * Copyright (C) 2023 Your Rents Team
 * %%
 * 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.
 * #L%
 */

import static com.yourrents.services.geodata.jooq.Tables.CONTINENT;
import static com.yourrents.services.geodata.jooq.Tables.COUNTRY;
import static com.yourrents.services.geodata.jooq.Tables.REGION;
import static org.jooq.Functions.nullOnAllNull;
import static org.jooq.Records.mapping;
import static org.jooq.impl.DSL.row;

import com.yourrents.services.common.searchable.Searchable;
import com.yourrents.services.common.util.exception.DataConflictException;
import com.yourrents.services.common.util.exception.DataNotFoundException;
import com.yourrents.services.common.util.jooq.JooqUtils;
import com.yourrents.services.geodata.jooq.tables.records.CountryRecord;
import com.yourrents.services.geodata.model.Country;
import com.yourrents.services.geodata.model.GeoReference;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record7;
import org.jooq.Select;
import org.jooq.SelectOnConditionStep;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class CountryRepository {

	private final DSLContext dsl;
	private final JooqUtils jooqUtils;

	CountryRepository(DSLContext dsl, JooqUtils jooqUtils) {
		this.dsl = dsl;
		this.jooqUtils = jooqUtils;
	}

	public Page find(Searchable filter, Pageable pageable) {
		Select result = jooqUtils.paginate(
				dsl,
				jooqUtils.getQueryWithConditionsAndSorts(getSelectCountrySpec(),
						filter, this::getSupportedSortField,
						pageable, this::getSupportedSortField),
				pageable.getPageSize(), pageable.getOffset());
		List countries = result.fetch(r ->
				new Country(
						r.get("uuid", UUID.class),
						r.get("isoCode", String.class),
						r.get("englishFullName", String.class),
						r.get("iso3", String.class),
						r.get("localName", String.class),
						r.get("number", Integer.class),
            r.get("continent", GeoReference.class))
		);
		int totalRows = Objects.requireNonNullElse(
				result.fetchAny("total_rows", Integer.class), 0);
		return new PageImpl<>(countries, pageable, totalRows);
	}


	public Optional findById(Integer id) {
		return getSelectCountrySpec()
				.where(COUNTRY.ID.eq(id))
				.fetchOptional()
				.map(mapping(Country::new));
	}

	public Optional findByExternalId(UUID externalId) {
		return getSelectCountrySpec()
				.where(COUNTRY.EXTERNAL_ID.eq(externalId))
				.fetchOptional()
				.map(mapping(Country::new));
	}

  /**
   * Create a new Country
   * @return the new created country
   */
  @Transactional(readOnly = false)
  public Country create(Country country) {
    Integer continentId = null;
    if (country.continent() != null && country.continent().uuid() != null) {
      continentId = dsl.select(CONTINENT.ID)
          .from(CONTINENT)
          .where(CONTINENT.EXTERNAL_ID.eq(country.continent().uuid()))
          .fetchOptional(CONTINENT.ID).orElseThrow(
              () -> new DataNotFoundException("Continent not found: "
                  + country.continent().uuid()));
    }
    CountryRecord newCountry = dsl.newRecord(COUNTRY);
    newCountry.setIsoCode(country.isoCode());
    newCountry.setEnglishFullName(country.englishFullName());
    newCountry.setIso_3(country.iso3());
    newCountry.setLocalName(country.localName());
    newCountry.setNumber(country.number());
    newCountry.setContinentId(continentId);
    newCountry.insert();
    return findById(newCountry.getId()).orElseThrow();
  }

  /**
   * Delete a country only if there are no regions associated with it.
   *
   * @return true if the country has been deleted, false otherwise
   * @throws DataNotFoundException if the country does not exist
   * @throws DataConflictException if there is at least one region associated to it
   */
  @Transactional(readOnly = false)
  public boolean delete(UUID uuid) {
    Integer countryId = dsl.select(COUNTRY.ID)
        .from(COUNTRY)
        .where(COUNTRY.EXTERNAL_ID.eq(uuid))
        .fetchOptional(COUNTRY.ID).orElseThrow(
            () -> new DataNotFoundException("Country not found: " + uuid));
    boolean regionExists = dsl.fetchExists(REGION, REGION.COUNTRY_ID.eq(countryId));
    if (regionExists) {
      throw new DataConflictException(
          "Unable to delete the country with UUID: " + uuid
              + " because it is referenced by at least one region");
    }
    return dsl.deleteFrom(COUNTRY)
        .where(COUNTRY.ID.eq(countryId))
        .execute() > 0;
  }


  /**
   * Update a country.
   * 

* You can update the name, the continent. You can't update the country uuid. *

* Only not null fields are used to update the country. * * @param uuid the uuid of the country to be updated. * @param country the data of country to be updated. * @return the updated country * @throws DataNotFoundException if the country does not exist */ @Transactional(readOnly = false) public Country update(UUID uuid, Country country) { CountryRecord dbCountry = dsl.selectFrom(COUNTRY) .where(COUNTRY.EXTERNAL_ID.eq(uuid)) .fetchOptional().orElseThrow( () -> new DataNotFoundException("Country not found: " + uuid)); if (country.isoCode() != null) { dbCountry.setIsoCode(country.isoCode()); } if (country.englishFullName() != null) { dbCountry.setEnglishFullName(country.englishFullName()); } if (country.iso3() != null) { dbCountry.setIso_3(country.iso3()); } if (country.localName() != null) { dbCountry.setLocalName(country.localName()); } if (country.number() != null) { dbCountry.setNumber(country.number()); } if (country.continent() != null && country.continent().uuid() != null) { Integer continentId = dsl.select(CONTINENT.ID) .from(CONTINENT) .where(CONTINENT.EXTERNAL_ID.eq(country.continent().uuid())) .fetchOptional(CONTINENT.ID).orElseThrow( () -> new IllegalArgumentException("Continent not found: " + country.continent().uuid())); dbCountry.setContinentId(continentId); } dbCountry.update(); return findById(dbCountry.getId()) .orElseThrow(() -> new RuntimeException("failed to update country: " + uuid)); } private SelectOnConditionStep> getSelectCountrySpec() { return dsl.select( COUNTRY.EXTERNAL_ID.as("uuid"), COUNTRY.ISO_CODE.as("isoCode"), COUNTRY.ENGLISH_FULL_NAME.as("englishFullName"), COUNTRY.ISO_3.as("iso3"), COUNTRY.LOCAL_NAME.as("localName"), COUNTRY.NUMBER.as("number"), row(CONTINENT.EXTERNAL_ID, CONTINENT.NAME) .mapping(nullOnAllNull(GeoReference::new)).as("continent")) .from(COUNTRY).leftJoin(CONTINENT) .on(COUNTRY.CONTINENT_ID.eq(CONTINENT.ID)); } private Field getSupportedSortField(String field) { return switch (field) { case "uuid" -> COUNTRY.EXTERNAL_ID; case "isoCode" -> COUNTRY.ISO_CODE; case "englishFullName" -> COUNTRY.ENGLISH_FULL_NAME; case "iso3" -> COUNTRY.ISO_3; case "localName" -> COUNTRY.LOCAL_NAME; case "number" -> COUNTRY.NUMBER; case "continent.name" -> COUNTRY.continent().NAME; default -> throw new IllegalArgumentException( "Unexpected value for filter/sort field: " + field); }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy