Browse Source

Polishing.

Original pull request #1403
See #1286
pull/1423/head
Jens Schauder 3 years ago
parent
commit
c5c60dadde
No known key found for this signature in database
GPG Key ID: 9537B67540F0A581
  1. 47
      spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java
  2. 4
      spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java
  3. 29
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-db2.sql
  4. 26
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-h2.sql
  5. 26
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-hsql.sql
  6. 26
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mariadb.sql
  7. 29
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mssql.sql
  8. 26
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mysql.sql
  9. 4
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-oracle.sql
  10. 29
      spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-postgres.sql

47
spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/SqlGenerator.java

@ -23,7 +23,6 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository; import org.springframework.data.jdbc.repository.support.SimpleJdbcRepository;
import org.springframework.data.mapping.PersistentPropertyPath; import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.relational.core.dialect.Dialect; import org.springframework.data.relational.core.dialect.Dialect;
import org.springframework.data.relational.core.dialect.RenderContextFactory; import org.springframework.data.relational.core.dialect.RenderContextFactory;
@ -697,13 +696,13 @@ class SqlGenerator {
private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) { private DeleteBuilder.DeleteWhereAndOr createBaseDeleteById(Table table) {
return Delete.builder().from(table) return Delete.builder().from(table) //
.where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER))); .where(getIdColumn().isEqualTo(getBindMarker(ID_SQL_PARAMETER)));
} }
private DeleteBuilder.DeleteWhereAndOr createBaseDeleteByIdIn(Table table) { private DeleteBuilder.DeleteWhereAndOr createBaseDeleteByIdIn(Table table) {
return Delete.builder().from(table) return Delete.builder().from(table) //
.where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER))); .where(getIdColumn().in(getBindMarker(IDS_SQL_PARAMETER)));
} }
@ -784,45 +783,37 @@ class SqlGenerator {
} }
private OrderByField orderToOrderByField(Sort.Order order) { private OrderByField orderToOrderByField(Sort.Order order) {
SqlIdentifier columnName = getColumnNameToSortBy(order); SqlIdentifier columnName = getColumnNameToSortBy(order);
Column column = Column.create(columnName, this.getTable()); Column column = Column.create(columnName, this.getTable());
return OrderByField.from(column, order.getDirection()).withNullHandling(order.getNullHandling()); return OrderByField.from(column, order.getDirection()).withNullHandling(order.getNullHandling());
} }
private SqlIdentifier getColumnNameToSortBy(Sort.Order order) { private SqlIdentifier getColumnNameToSortBy(Sort.Order order) {
SqlIdentifier columnName = null;
RelationalPersistentProperty propertyToSortBy = entity.getPersistentProperty(order.getProperty()); RelationalPersistentProperty propertyToSortBy = entity.getPersistentProperty(order.getProperty());
if (propertyToSortBy != null) { if (propertyToSortBy != null) {
return propertyToSortBy.getColumnName(); return propertyToSortBy.getColumnName();
} }
PersistentPropertyPath<RelationalPersistentProperty> persistentPropertyPath = mappingContext.getPersistentPropertyPath( PersistentPropertyPath<RelationalPersistentProperty> persistentPropertyPath = mappingContext
order.getProperty(), entity.getType() .getPersistentPropertyPath(order.getProperty(), entity.getType());
);
propertyToSortBy = persistentPropertyPath.getBaseProperty(); propertyToSortBy = persistentPropertyPath.getBaseProperty();
if (propertyToSortBy == null || !propertyToSortBy.isEmbedded()) { Assert.state(propertyToSortBy != null && propertyToSortBy.isEmbedded(), () -> String.format( //
throwPropertyNotMarkedAsEmbeddedException(order); "Specified sorting property '%s' is expected to " + //
} else { "be the property, named '%s', of embedded entity '%s', but field '%s' is " + //
RelationalPersistentEntity<?> embeddedEntity = mappingContext.getRequiredPersistentEntity(propertyToSortBy.getType()); "not marked with @Embedded", //
columnName = embeddedEntity.getRequiredPersistentProperty(extractFieldNameFromEmbeddedProperty(order)).getColumnName(); order.getProperty(), //
} extractFieldNameFromEmbeddedProperty(order), //
return columnName; extractEmbeddedPropertyName(order), //
} extractEmbeddedPropertyName(order) //
));
private void throwPropertyNotMarkedAsEmbeddedException(Sort.Order order) {
throw new IllegalArgumentException( RelationalPersistentEntity<?> embeddedEntity = mappingContext
String.format( .getRequiredPersistentEntity(propertyToSortBy.getType());
"Specified sorting property '%s' is expected to " + return embeddedEntity.getRequiredPersistentProperty(extractFieldNameFromEmbeddedProperty(order)).getColumnName();
"be the property, named '%s', of embedded entity '%s', but field '%s' is " +
"not marked with @Embedded",
order.getProperty(),
extractFieldNameFromEmbeddedProperty(order),
extractEmbeddedPropertyName(order),
extractEmbeddedPropertyName(order)
)
);
} }
public String extractEmbeddedPropertyName(Sort.Order order) { public String extractEmbeddedPropertyName(Sort.Order order) {

4
spring-data-jdbc/src/test/java/org/springframework/data/jdbc/repository/JdbcRepositoryEmbeddedIntegrationTests.java

@ -92,7 +92,6 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
@Autowired NamedParameterJdbcTemplate template; @Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository; @Autowired DummyEntityRepository repository;
@Autowired PersonRepository personRepository; @Autowired PersonRepository personRepository;
@Autowired WithDotColumnRepo withDotColumnRepo; @Autowired WithDotColumnRepo withDotColumnRepo;
@Test // DATAJDBC-111 @Test // DATAJDBC-111
@ -246,6 +245,7 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
@Test // GH-1286 @Test // GH-1286
public void findOrderedByEmbeddedProperty() { public void findOrderedByEmbeddedProperty() {
Person first = new Person(null, "Bob", "Seattle", new PersonContacts("ddd@example.com", "+1 111 1111 11 11")); Person first = new Person(null, "Bob", "Seattle", new PersonContacts("ddd@example.com", "+1 111 1111 11 11"));
Person second = new Person(null, "Alex", "LA", new PersonContacts("aaa@example.com", "+2 222 2222 22 22")); Person second = new Person(null, "Alex", "LA", new PersonContacts("aaa@example.com", "+2 222 2222 22 22"));
Person third = new Person(null, "Sarah", "NY", new PersonContacts("ggg@example.com", "+3 333 3333 33 33")); Person third = new Person(null, "Sarah", "NY", new PersonContacts("ggg@example.com", "+3 333 3333 33 33"));
@ -254,7 +254,6 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
Iterable<Person> fetchedPersons = personRepository.findAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "personContacts.email"))); Iterable<Person> fetchedPersons = personRepository.findAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "personContacts.email")));
Assertions.assertThat(fetchedPersons).hasSize(3);
Assertions.assertThat(fetchedPersons).containsExactly(second, first, third); Assertions.assertThat(fetchedPersons).containsExactly(second, first, third);
} }
@ -269,7 +268,6 @@ public class JdbcRepositoryEmbeddedIntegrationTests {
Iterable<WithDotColumn> fetchedPersons = withDotColumnRepo.findAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "address"))); Iterable<WithDotColumn> fetchedPersons = withDotColumnRepo.findAll(Sort.by(new Sort.Order(Sort.Direction.ASC, "address")));
Assertions.assertThat(fetchedPersons).hasSize(3);
Assertions.assertThat(fetchedPersons).containsExactly(second, first, third); Assertions.assertThat(fetchedPersons).containsExactly(second, first, third);
} }

29
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-db2.sql

@ -1,8 +1,27 @@
DROP TABLE dummy_entity; DROP TABLE dummy_entity;
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);
DROP TABLE SORT_EMBEDDED_ENTITY; DROP TABLE SORT_EMBEDDED_ENTITY;
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255));
DROP TABLE WITH_DOT_COLUMN; DROP TABLE WITH_DOT_COLUMN;
CREATE TABLE WITH_DOT_COLUMN (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, "address.city" VARCHAR(255));
CREATE TABLE dummy_entity
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
"address.city" VARCHAR(255)
);

26
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-h2.sql

@ -1,3 +1,23 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT); CREATE TABLE dummy_entity
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255)); (
CREATE TABLE WITH_DOT_COLUMN (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, "address.city" VARCHAR(255)); id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
"address.city" VARCHAR(255)
);

26
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-hsql.sql

@ -1,3 +1,23 @@
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT); CREATE TABLE dummy_entity
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255)); (
CREATE TABLE WITH_DOT_COLUMN (id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, "address.city" VARCHAR(255)); id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
"address.city" VARCHAR(255)
);

26
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mariadb.sql

@ -1,3 +1,23 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT); CREATE TABLE dummy_entity
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255)); (
CREATE TABLE WITH_DOT_COLUMN (id BIGINT AUTO_INCREMENT PRIMARY KEY, `address.city` VARCHAR(255)); id BIGINT AUTO_INCREMENT PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
`address.city` VARCHAR(255)
);

29
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mssql.sql

@ -1,8 +1,27 @@
DROP TABLE IF EXISTS dummy_entity; DROP TABLE IF EXISTS dummy_entity;
CREATE TABLE dummy_entity (id BIGINT IDENTITY PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);
DROP TABLE IF EXISTS SORT_EMBEDDED_ENTITY; DROP TABLE IF EXISTS SORT_EMBEDDED_ENTITY;
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT IDENTITY PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255));
DROP TABLE IF EXISTS WITH_DOT_COLUMN; DROP TABLE IF EXISTS WITH_DOT_COLUMN;
CREATE TABLE WITH_DOT_COLUMN (id BIGINT IDENTITY PRIMARY KEY, "address.city" VARCHAR(255));
CREATE TABLE dummy_entity
(
id BIGINT IDENTITY PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT IDENTITY PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT IDENTITY PRIMARY KEY,
"address.city" VARCHAR(255)
);

26
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-mysql.sql

@ -1,3 +1,23 @@
CREATE TABLE dummy_entity (id BIGINT AUTO_INCREMENT PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT); CREATE TABLE dummy_entity
CREATE TABLE SORT_EMBEDDED_ENTITY (id BIGINT AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255)); (
CREATE TABLE WITH_DOT_COLUMN (id BIGINT AUTO_INCREMENT PRIMARY KEY, `address.city` VARCHAR(255)); id BIGINT AUTO_INCREMENT PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE SORT_EMBEDDED_ENTITY
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
`address.city` VARCHAR(255)
);

4
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-oracle.sql

@ -1,4 +1,6 @@
DROP TABLE DUMMY_ENTITY CASCADE CONSTRAINTS PURGE; DROP TABLE DUMMY_ENTITY CASCADE CONSTRAINTS PURGE;
DROP TABLE SORT_EMBEDDED_ENTITY CASCADE CONSTRAINTS PURGE;
DROP TABLE WITH_DOT_COLUMN CASCADE CONSTRAINTS PURGE;
CREATE TABLE DUMMY_ENTITY ( CREATE TABLE DUMMY_ENTITY (
ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY, ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
@ -8,7 +10,6 @@ CREATE TABLE DUMMY_ENTITY (
PREFIX_PREFIX2_ATTR NUMBER PREFIX_PREFIX2_ATTR NUMBER
); );
DROP TABLE SORT_EMBEDDED_ENTITY CASCADE CONSTRAINTS PURGE;
CREATE TABLE SORT_EMBEDDED_ENTITY ( CREATE TABLE SORT_EMBEDDED_ENTITY (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY, id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,
@ -18,7 +19,6 @@ CREATE TABLE SORT_EMBEDDED_ENTITY (
phone_number VARCHAR(255) phone_number VARCHAR(255)
); );
DROP TABLE WITH_DOT_COLUMN CASCADE CONSTRAINTS PURGE;
CREATE TABLE WITH_DOT_COLUMN ( CREATE TABLE WITH_DOT_COLUMN (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY, id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY PRIMARY KEY,

29
spring-data-jdbc/src/test/resources/org.springframework.data.jdbc.repository/JdbcRepositoryEmbeddedIntegrationTests-postgres.sql

@ -1,8 +1,27 @@
DROP TABLE dummy_entity; DROP TABLE dummy_entity;
CREATE TABLE dummy_entity (id SERIAL PRIMARY KEY, TEST VARCHAR(100), PREFIX2_ATTR BIGINT, PREFIX_TEST VARCHAR(100), PREFIX_PREFIX2_ATTR BIGINT);
DROP TABLE "SORT_EMBEDDED_ENTITY"; DROP TABLE "SORT_EMBEDDED_ENTITY";
CREATE TABLE "SORT_EMBEDDED_ENTITY" (id SERIAL PRIMARY KEY, first_name VARCHAR(100), address VARCHAR(255), email VARCHAR(255), phone_number VARCHAR(255));
DROP TABLE WITH_DOT_COLUMN; DROP TABLE WITH_DOT_COLUMN;
CREATE TABLE WITH_DOT_COLUMN (id SERIAL PRIMARY KEY, "address.city" VARCHAR(255));
CREATE TABLE dummy_entity
(
id SERIAL PRIMARY KEY,
TEST VARCHAR(100),
PREFIX2_ATTR BIGINT,
PREFIX_TEST VARCHAR(100),
PREFIX_PREFIX2_ATTR BIGINT
);
CREATE TABLE "SORT_EMBEDDED_ENTITY"
(
id SERIAL PRIMARY KEY,
first_name VARCHAR(100),
address VARCHAR(255),
email VARCHAR(255),
phone_number VARCHAR(255)
);
CREATE TABLE WITH_DOT_COLUMN
(
id SERIAL PRIMARY KEY,
"address.city" VARCHAR(255)
);
Loading…
Cancel
Save