Reflect grouping in directory structure

This commit is contained in:
Andy Wilkinson
2022-10-28 14:36:50 +01:00
parent 393e1cb6bf
commit 7112a4b6a4
788 changed files with 9 additions and 100 deletions

View File

@@ -0,0 +1,67 @@
package com.example.data.cassandra;
import static org.assertj.core.api.Assertions.*;
import java.time.Duration;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;
import org.springframework.aot.smoketest.support.assertj.AssertableOutput;
import org.springframework.aot.smoketest.support.junit.ApplicationTest;
@ApplicationTest
class DataCassandraApplicationAotTests {
@Test
void auditing(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasLineContaining("modifiedBy=Douglas Adams");
});
}
@Test
void resultSorting(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasLineContaining("sortedByCustomer: [Order{id='o1', customerId='c42'");
});
}
@Test
void resultSlice(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasLineContaining("c42_slice0: Slice 0");
});
}
@Test
void derivedQuery(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasLineContaining("derivedQuery: Order{id=");
});
}
@Test
void resultProjection(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasLineContaining("OrderProjection($Proxy");
});
}
@Test
void findAll(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output).hasSingleLineContaining("findAll(): Person{firstname='first-1', lastname='last-1'}")
.hasSingleLineContaining("findAll(): Person{firstname='first-2', lastname='last-2'}")
.hasSingleLineContaining("findAll(): Person{firstname='first-3', lastname='last-3'}");
});
}
@Test
void findByLastName(AssertableOutput output) {
Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> {
assertThat(output)
.hasSingleLineContaining("findByLastname(): Person{firstname='first-3', lastname='last-3'}");
});
}
}

View File

@@ -0,0 +1,139 @@
package com.example.data.cassandra;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
@Component
class CLR implements CommandLineRunner {
@Autowired
private PersonRepository personRepository;
@Autowired
private CassandraTemplate template;
@Autowired
private OrderRepository orderRepository;
@Override
public void run(String... args) throws Exception {
this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-1", "last-1"));
this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-2", "last-2"));
this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-3", "last-3"));
for (Person person : this.personRepository.findAll()) {
System.out.printf("findAll(): %s%n", person);
}
for (Person person : this.personRepository.findByLastname("last-3")) {
System.out.printf("findByLastname(): %s%n", person);
}
LineItem product1 = new LineItem("p1", 1.23);
LineItem product2 = new LineItem("p2", 0.87, 2);
LineItem product3 = new LineItem("p3", 5.33);
runPagingAndSorting(product1, product2, product3);
runPartTreeQuery(product1, product2, product3);
runResultProjection(product1, product2, product3);
}
// Paging and Sorting with Repository
private void runPagingAndSorting(LineItem product1, LineItem product2, LineItem product3) {
log("---- Paging / Sorting ----");
orderRepository.deleteAll();
orderRepository.save(newOrder("o1", "c42", product1, product2, product3));
orderRepository.save(newOrder("o2", "c42", product1));
orderRepository.save(newOrder("o3", "c42", product2));
orderRepository.save(newOrder("o4", "c42", product3));
orderRepository.save(newOrder("o5", "b12", product1));
orderRepository.save(newOrder("o6", "b12", product1));
// sort
List<Order> sortedByCustomer = orderRepository.findById("o1", Sort.by("customerId"));
log("sortedByCustomer: %s", sortedByCustomer);
// page
// slice
Slice<Order> c42_slice0 = orderRepository.findSliceByCustomerId("c42", PageRequest.of(0, 2));
log("c42_slice0: %s", c42_slice0);
Slice<Order> c42_slice1 = orderRepository.findSliceByCustomerId("c42", c42_slice0.nextPageable());
log("c42_slice1: %s", c42_slice1);
log("-----------------\n\n\n");
}
// Part Tree Query
private void runPartTreeQuery(LineItem product1, LineItem product2, LineItem product3) {
log("---- PART TREE QUERY ----");
orderRepository.deleteAll();
Order order = newOrder("o7", "c42", product1, product2, product3);
orderRepository.save(order);
List<Order> byCustomerId = orderRepository.findByCustomerId(order.getCustomerId());
System.out.print("derivedQuery: ");
byCustomerId.forEach(this::log);
byCustomerId.forEach(this::log);
log("-----------------\n\n\n");
}
// Query with Result Projection
private void runResultProjection(LineItem product1, LineItem product2, LineItem product3) {
log("---- RESULT PROJECTION ----");
orderRepository.deleteAll();
Order order = newOrder("o9", "c42", product1, product2, product3);
orderRepository.save(order);
List<OrderProjection> result = orderRepository.findProjectionByCustomerId(order.getCustomerId());
result.forEach(it -> log("OrderProjection(%s){id=%s, customerId=%s}", it.getClass().getSimpleName(), it.getId(),
it.getCustomerId()));
log("-----------------\n\n\n");
}
private Order newOrder(String id, String customerId, LineItem... items) {
return newOrder(id, customerId, new Date(), items);
}
private Order newOrder(String id, String customerId, Date date, LineItem... items) {
Order order = new Order(id, customerId, date, new ArrayList<>());
Arrays.stream(items).forEach(order::addItem);
return order;
}
private void log(Object value) {
log(String.valueOf(value), new Object[0]);
}
private void log(String message, Object... arguments) {
String messageNewline = String.valueOf(message).endsWith("\n") ? message : message + "\n";
System.out.printf(messageNewline, arguments);
System.out.flush();
}
}

View File

@@ -0,0 +1,25 @@
package com.example.data.cassandra;
import com.datastax.oss.driver.api.core.CqlSession;
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.cql.generator.CreateKeyspaceCqlGenerator;
import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification;
@Configuration
class CassandraConfiguration {
@Bean
CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) {
// This creates the keyspace on startup
try (CqlSession session = cqlSessionBuilder.withKeyspace((String) null).build()) {
session.execute(CreateKeyspaceCqlGenerator
.toCql(CreateKeyspaceSpecification.createKeyspace(properties.getKeyspaceName()).ifNotExists()));
}
return cqlSessionBuilder.withKeyspace(properties.getKeyspaceName()).build();
}
}

View File

@@ -0,0 +1,25 @@
package com.example.data.cassandra;
import java.util.Optional;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.cassandra.config.EnableCassandraAuditing;
import org.springframework.data.domain.AuditorAware;
@SpringBootApplication
@EnableCassandraAuditing(auditorAwareRef = "fixedAuditor")
public class DataCassandraApplication {
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(DataCassandraApplication.class, args);
Thread.currentThread().join(); // To be able to measure memory consumption
}
@Bean
AuditorAware<String> fixedAuditor() {
return () -> Optional.of("Douglas Adams");
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.cassandra.core.mapping.Element;
import org.springframework.data.cassandra.core.mapping.Tuple;
@Tuple
public class LineItem {
@Element(0)
private final String caption;
@Element(1)
private final double price;
@Element(2)
int quantity = 1;
public LineItem(String caption, double price) {
this.caption = caption;
this.price = price;
}
@PersistenceCreator
public LineItem(String caption, double price, int quantity) {
this(caption, price);
this.quantity = quantity;
}
public String getCaption() {
return caption;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
@Override
public String toString() {
return "LineItem{" + "caption='" + caption + '\'' + ", price=" + price + ", quantity=" + quantity + '}';
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.cassandra.core.cql.PrimaryKeyType;
import org.springframework.data.cassandra.core.mapping.Column;
import org.springframework.data.cassandra.core.mapping.Indexed;
import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.core.mapping.Table;
@Table("orders")
public class Order {
@PrimaryKeyColumn(type = PrimaryKeyType.PARTITIONED, ordinal = 0)
private String id;
@PrimaryKeyColumn(ordinal = 1)
@Indexed
private String customerId;
@Column("order_date")
private Date orderDate;
private List<LineItem> items;
@CreatedDate
Instant createdAt;
@CreatedBy
String createdBy;
@LastModifiedDate
Instant modifiedAt;
@LastModifiedBy
String modifiedBy;
protected Order() {
}
protected Order(String customerId) {
this(customerId, null);
}
@PersistenceConstructor
public Order(String id, String customerId, Date orderDate, List<LineItem> items) {
this.id = id;
this.customerId = customerId;
this.orderDate = orderDate;
this.items = items;
}
/**
* Creates a new {@link Order} for the given customer id and order date.
* @param customerId {@link String ID} of the {@literal customer}.
* @param orderDate {@link Date} of this {@link Order}.
*/
public Order(String customerId, Date orderDate) {
this(null, customerId, orderDate, new ArrayList<>());
}
/**
* Adds a {@link LineItem} to the {@link Order}.
* @param item {@link LineItem Item} ordered.
* @return this {@link Order}.
*/
public Order addItem(LineItem item) {
this.items.add(item);
return this;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
public List<LineItem> getItems() {
return items;
}
public void setItems(List<LineItem> items) {
this.items = items;
}
@Override
public String toString() {
return "Order{" + "id='" + id + '\'' + ", customerId='" + customerId + '\'' + ", orderDate=" + orderDate
+ ", items=" + items + ", createdAt=" + createdAt + ", createdBy=" + createdBy + ", modifiedAt="
+ modifiedAt + ", modifiedBy=" + modifiedBy + '}';
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
public interface OrderProjection {
String getId();
String getCustomerId();
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
import java.util.List;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;
public interface OrderRepository extends CrudRepository<Order, String>, OrderRepositoryCustom {
List<Order> findByCustomerId(String customerId);
List<OrderProjection> findProjectionByCustomerId(String customerId);
Slice<Order> findSliceByCustomerId(String customerId, Pageable pageable);
List<Order> findById(String id, Sort sort);
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
public interface OrderRepositoryCustom {
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2022 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Indexed;
@Component
class OrderRepositoryImpl implements OrderRepositoryCustom {
}

View File

@@ -0,0 +1,59 @@
package com.example.data.cassandra;
import org.springframework.data.cassandra.core.mapping.Column;
import org.springframework.data.cassandra.core.mapping.Indexed;
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
import org.springframework.data.cassandra.core.mapping.Table;
@Table
public class Person {
@PrimaryKey
private String id;
@Column
private String firstname;
@Column
@Indexed
private String lastname;
public Person() {
}
public Person(String id, String firstname, String lastname) {
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
@Override
public String toString() {
return "Person{" + "firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + '}';
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2020 the original author or authors.
*
* 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
*
* https://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.example.data.cassandra;
import java.util.List;
import org.springframework.data.repository.ListCrudRepository;
public interface PersonRepository extends ListCrudRepository<Person, String> {
List<Person> findByLastname(String lastname);
}

View File

@@ -0,0 +1,4 @@
spring.cassandra.contact-points=${CASSANDRA_HOST:127.0.0.1}:${CASSANDRA_PORT_9042:9042}
spring.cassandra.local-datacenter=datacenter1
spring.cassandra.keyspace-name=example
spring.cassandra.schema-action=recreate