diff --git a/spring-cloud-oci/docs/src/main/asciidoc/index.adoc b/spring-cloud-oci/docs/src/main/asciidoc/index.adoc
index f8706233..bbdaa1e5 100644
--- a/spring-cloud-oci/docs/src/main/asciidoc/index.adoc
+++ b/spring-cloud-oci/docs/src/main/asciidoc/index.adoc
@@ -30,6 +30,8 @@ include::storage.adoc[]
include::notifications.adoc[]
+include::nosql.adoc[]
+
include::queues.adoc[]
include::streaming.adoc[]
diff --git a/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc b/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc
new file mode 100644
index 00000000..2ec84972
--- /dev/null
+++ b/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc
@@ -0,0 +1,97 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+
+[#oci-nosql]
+== Oracle NoSQL Database
+
+https://docs.oracle.com/en-us/iaas/nosql-database/index.html[Oracle NoSQL Database] service offering on-demand throughput and storage based provisioning that supports JSON, Table and Key-Value datatypes, all with flexible transaction guarantees.
+
+Maven coordinates:
+
+[source,xml]
+----
+
+ com.oracle.cloud.spring
+ spring-cloud-oci-starter-nosql
+
+----
+
+Gradle coordinates:
+
+[source,subs="normal"]
+----
+dependencies {
+ implementation("com.oracle.cloud.spring:spring-cloud-oci-starter-nosql")
+}
+----
+
+=== Using Oracle NoSQL Database
+
+The starter automatically configures and registers a `NosqlDBConfig` bean in the Spring application, allowing the use of Oracle NoSQL Database repositories.
+
+[source,yaml]
+----
+spring:
+ cloud:
+ oci:
+ config:
+ type: file
+ region:
+ static: us-ashburn-1
+----
+
+Enable NoSQL repositories in your application by using the `@EnableNosqlRepositories` annotation and extending the `AbstractNosqlConfiguration` class.
+
+[source,java]
+----
+import com.oracle.nosql.spring.data.config.AbstractNosqlConfiguration;
+import com.oracle.nosql.spring.data.repository.config.EnableNosqlRepositories;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableNosqlRepositories
+public class MyApp extends AbstractNosqlConfiguration {
+ public static void main(String[] args) {
+ SpringApplication.run(MyApp.class, args);
+ }
+}
+----
+
+NoSQL repositories and tables are simply defined by extending the `NosqlRepository` interface and applying the `@NosqlTable` annotation:
+
+[source,java]
+----
+public interface BookRepository extends NosqlRepository {
+ // Add repository methods as needed.
+ Iterable findByAuthor(String author);
+ Iterable findByTitle(String title);
+}
+----
+
+[source,java]
+----
+@NosqlTable(tableName = "books")
+public class Book {
+ @NosqlId(generated = true)
+ long id;
+ String title;
+ String author;
+ double price;
+}
+----
+
+
+=== Configuration
+
+The Spring Boot Starter for Oracle Cloud NoSQL Database provides the following configuration options:
+
+|===
+^| Name ^| Description ^| Required ^| Default value
+| `spring.cloud.oci.nosql.enabled` | Enables the NoSQL DB Config. | No | `true`
+|===
+
+
+=== Sample
+
+A sample application provided https://github.com/oracle/spring-cloud-oracle/tree/main/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample[here] contains the examples to demonstrates the usage of OCI Spring Cloud NoSQL module.
diff --git a/spring-cloud-oci/pom.xml b/spring-cloud-oci/pom.xml
index e4431d2b..c68fe6c7 100644
--- a/spring-cloud-oci/pom.xml
+++ b/spring-cloud-oci/pom.xml
@@ -75,6 +75,8 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
${project.version}
2023.0.2
6.1.10
+ 2.0.0
+ 5.4.15
2.0.3
3.44.3
17
@@ -172,6 +174,46 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
${spring-framework.version}
compile
+
+ com.oracle.nosql.sdk
+ spring-data-oracle-nosql
+ ${spring-data-oracle-nosql.version}
+
+
+ com.oracle.nosql.sdk
+ nosqldriver
+ ${oracle.nosql.driver.version}
+
+
+ org.springframework.data
+ spring-data-commons
+ ${spring-boot.version}
+
+
+ org.springframework
+ spring-core
+ ${spring-framework.version}
+
+
+ org.springframework
+ spring-tx
+ ${spring-framework.version}
+
+
+ org.springframework
+ spring-expression
+ ${spring-framework.version}
+
+
+ org.springframework
+ spring-beans
+ ${spring-framework.version}
+
+
+ org.springframework
+ spring-context
+ ${spring-framework.version}
+
org.eclipse.angus
jakarta.mail
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml b/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml
index c2bf5dfd..774c81df 100644
--- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml
@@ -100,6 +100,11 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
spring-cloud-oci-logging
true
+
+ com.oracle.nosql.sdk
+ spring-data-oracle-nosql
+ true
+
com.oracle.cloud.spring
spring-cloud-oci-function
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java
new file mode 100644
index 00000000..3dafc2d2
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java
@@ -0,0 +1,64 @@
+/*
+ ** Copyright (c) 2024, Oracle and/or its affiliates.
+ ** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+ */
+package com.oracle.cloud.spring.nosql;
+
+import java.io.IOException;
+
+import com.oracle.bmc.auth.RegionProvider;
+import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties;
+import com.oracle.nosql.spring.data.config.NosqlDbConfig;
+import oracle.nosql.driver.iam.SignatureProvider;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Bean;
+
+import static com.oracle.cloud.spring.autoconfigure.core.RegionProviderAutoConfiguration.regionProviderQualifier;
+
+@AutoConfiguration
+@ConditionalOnClass(NosqlDbConfig.class)
+@ConditionalOnProperty(name = "spring.cloud.oci.nosql.enabled", havingValue = "true", matchIfMissing = true)
+public class NoSQLAutoConfiguration {
+ @Bean
+ @RefreshScope
+ @ConditionalOnMissingBean
+ public NosqlDbConfig nosqlDbConfig(@Qualifier(regionProviderQualifier) RegionProvider regionProvider,
+ CredentialsProperties properties) throws IOException {
+ String profile = properties.hasProfile() ? properties.getProfile() : "DEFAULT";
+ SignatureProvider signatureProvider;
+ switch (properties.getType()) {
+ case WORKLOAD_IDENTITY -> signatureProvider = SignatureProvider.createWithOkeWorkloadIdentity();
+ case RESOURCE_PRINCIPAL -> signatureProvider = SignatureProvider.createWithResourcePrincipal();
+ case INSTANCE_PRINCIPAL ->
+ signatureProvider = SignatureProvider.createWithInstancePrincipal();
+ case SIMPLE -> signatureProvider = new SignatureProvider(
+ properties.getTenantId(),
+ properties.getUserId(),
+ properties.getFingerprint(),
+ properties.getPrivateKey(),
+ properties.getPassPhrase() != null ? properties.getPassPhrase().toCharArray() : null
+ );
+ case SESSION_TOKEN -> {
+ if (properties.hasFile()) {
+ signatureProvider = SignatureProvider.createWithSessionToken(properties.getFile(), profile);
+ } else {
+ signatureProvider = SignatureProvider.createWithSessionToken(profile);
+ }
+ }
+ default -> {
+ if (properties.hasFile()) {
+ signatureProvider = new SignatureProvider(properties.getFile(), profile);
+ } else {
+ signatureProvider = new SignatureProvider(profile);
+ }
+
+ }
+ }
+ return new NosqlDbConfig(regionProvider.getRegion().getRegionId(), signatureProvider);
+ }
+}
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index ebdbd56f..9d2965a0 100644
--- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -65,6 +65,12 @@
"type": "java.lang.Boolean",
"description": "Auto-configure OCI Autonomous Database components.",
"defaultValue": true
+ },
+ {
+ "name": "spring.cloud.oci.nosql.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Auto-configure Oracle NoSQL Database components.",
+ "defaultValue": true
}
]
}
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index fd16f8d8..e960b8c9 100644
--- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -11,3 +11,4 @@ com.oracle.cloud.spring.genai.GenAIAutoConfiguration
com.oracle.cloud.spring.vault.VaultAutoConfiguration
com.oracle.cloud.spring.adb.AutonomousDbAutoConfiguration
com.oracle.cloud.spring.email.EmailDeliveryAutoConfiguration
+com.oracle.cloud.spring.nosql.NoSQLAutoConfiguration
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java
index 78252811..07c2c32c 100644
--- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java
@@ -8,16 +8,24 @@
import com.oracle.bmc.Region;
import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider;
import com.oracle.bmc.auth.RegionProvider;
+import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties;
import com.oracle.cloud.spring.core.compartment.CompartmentProvider;
import com.oracle.cloud.spring.core.compartment.StaticCompartmentProvider;
import com.oracle.cloud.spring.core.region.StaticRegionProvider;
+import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Configuration
public class TestCommonConfigurationBeans {
+ @Bean
+ CredentialsProperties credentialsProperties() {
+ return new CredentialsProperties();
+ }
+
@Bean
BasicAuthenticationDetailsProvider credentialsProvider() {
return mock(BasicAuthenticationDetailsProvider.class);
@@ -33,4 +41,17 @@ CompartmentProvider compartmentProvider() {
return new StaticCompartmentProvider("compartmentOCID");
}
+ public static void assertBeanLoaded(AssertableApplicationContext ctx, Class> clazz) {
+ assertBeanLoaded(ctx, clazz, true);
+ }
+
+ public static void assertBeanNotLoaded(AssertableApplicationContext ctx, Class> clazz) {
+ assertBeanLoaded(ctx, clazz, false);
+ }
+
+ static void assertBeanLoaded(AssertableApplicationContext ctx, Class> clazz, boolean loaded) {
+ String[] beans = ctx.getBeanNamesForType(clazz);
+ assertThat(beans).hasSize(loaded ? 2 : 0);
+ }
+
}
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java
new file mode 100644
index 00000000..d96d3e91
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.nosql;
+
+import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans;
+import com.oracle.nosql.spring.data.config.NosqlDbConfig;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+
+import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded;
+import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded;
+
+public class NoSQLAutoConfigurationTests {
+ private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withPropertyValues("spring.cloud.oci.nosql.enabled=true")
+ .withConfiguration(AutoConfigurations.of(NoSQLAutoConfiguration.class))
+ .withUserConfiguration(TestCommonConfigurationBeans.class);
+
+ @Test
+ void beansAreLoaded() {
+ contextRunner.run(ctx -> assertBeanLoaded(ctx, NosqlDbConfig.class));
+ }
+
+ @Test
+ void beansAreNotLoadedWhenDisabled() {
+ contextRunner.withPropertyValues("spring.cloud.oci.nosql.enabled=false")
+ .run(ctx -> assertBeanNotLoaded(ctx, NosqlDbConfig.class));
+ }
+}
diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java
index f21236c7..2dfbc516 100644
--- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java
+++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java
@@ -5,10 +5,10 @@
import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import static org.assertj.core.api.Assertions.assertThat;
+import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded;
+import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded;
public class VaultAutoConfigurationTests {
private final String vaultIdProperty = "spring.cloud.oci.vault.vault-id=xyz";
@@ -22,23 +22,18 @@ public class VaultAutoConfigurationTests {
@Test
void beansAreLoaded() {
contextRunner.withPropertyValues(vaultIdProperty)
- .run(ctx -> assertVaultTemplateBean(ctx, true));
+ .run(ctx -> assertBeanLoaded(ctx, VaultTemplate.class));
}
@Test
void beansAreNotLoadedWhenDisabled() {
contextRunner.withPropertyValues(vaultIdProperty,
"spring.cloud.oci.vault.enabled=false")
- .run(ctx -> assertVaultTemplateBean(ctx, false));
+ .run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class));
}
@Test
void beansAreNotLoadedWhenNoVault() {
- contextRunner.run(ctx -> assertVaultTemplateBean(ctx, false));
- }
-
- private void assertVaultTemplateBean(AssertableApplicationContext ctx, boolean hasBean) {
- String[] beans = ctx.getBeanNamesForType(VaultTemplate.class);
- assertThat(beans).hasSize(hasBean ? 2 : 0);
+ contextRunner.run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class));
}
}
diff --git a/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml b/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml
index bf13918e..80c10722 100644
--- a/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml
+++ b/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml
@@ -157,6 +157,11 @@
spring-cloud-oci-starter-email
${project.version}
+
+ com.oracle.cloud.spring
+ spring-cloud-oci-starter-nosql
+ ${project.version}
+
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/pom.xml b/spring-cloud-oci/spring-cloud-oci-samples/pom.xml
index ef7f13f2..0e0f2b90 100644
--- a/spring-cloud-oci/spring-cloud-oci-samples/pom.xml
+++ b/spring-cloud-oci/spring-cloud-oci-samples/pom.xml
@@ -50,6 +50,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
spring-cloud-oci-function-sample
spring-cloud-oci-adb-sample
spring-cloud-oci-email-sample
+ spring-cloud-oci-nosql-sample
spring-cloud-oci-samples
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml
new file mode 100644
index 00000000..e2fea8bf
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+
+
+ com.oracle.cloud.spring
+ spring-cloud-oci-samples
+ 1.3.0-SNAPSHOT
+
+ 4.0.0
+ com.oracle.cloud.spring.sample.nosql
+ spring-cloud-oci-nosql-sample
+ spring-cloud-oci-nosql-sample
+ spring-cloud-oci-nosql-sample
+
+
+ Oracle America, Inc.
+ https://www.oracle.com
+
+
+
+
+ Oracle
+ obaas_ww at oracle.com
+ Oracle America, Inc.
+ https://www.oracle.com
+
+
+
+
+
+ The Universal Permissive License (UPL), Version 1.0
+ https://oss.oracle.com/licenses/upl/
+ repo
+
+
+
+
+ https://github.com/oracle/spring-cloud-oracle
+ scm:git:https://github.com/oracle/spring-cloud-oracle.git
+ scm:git:git@github.com:oracle/spring-cloud-oracle.git
+
+
+
+ 17
+
+
+
+ com.oracle.cloud.spring
+ spring-cloud-oci-starter-nosql
+
+
+ com.oracle.cloud.spring.sample.common
+ spring-cloud-oci-common-samples-utils
+
+
+ com.oracle.cloud.spring.sample.common
+ spring-cloud-oci-common-samples-utils
+ test-jar
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java
new file mode 100644
index 00000000..3f67d551
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample;
+
+import com.oracle.nosql.spring.data.core.mapping.NosqlId;
+import com.oracle.nosql.spring.data.core.mapping.NosqlTable;
+
+// Requires a NoSQL table named "books" in your OCI Account.
+@NosqlTable(tableName = "books")
+public class Book {
+ @NosqlId(generated = true)
+ long id;
+ String title;
+ String author;
+ double price;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof Book book)) return false;
+
+ return getId() == book.getId() && Double.compare(getPrice(), book.getPrice()) == 0 && getTitle().equals(book.getTitle()) && getAuthor().equals(book.getAuthor());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Long.hashCode(getId());
+ result = 31 * result + getTitle().hashCode();
+ result = 31 * result + getAuthor().hashCode();
+ result = 31 * result + Double.hashCode(getPrice());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Book{" +
+ "id=" + id +
+ ", title='" + title + '\'' +
+ ", author='" + author + '\'' +
+ ", price=" + price +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java
new file mode 100644
index 00000000..de4ddaea
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/books")
+public class BookController {
+ private final BookRepository bookRepository;
+
+ public BookController(BookRepository bookRepository) {
+ this.bookRepository = bookRepository;
+ }
+
+ @GetMapping
+ public ResponseEntity> getAllBooks(@RequestParam(name = "title", required = false) String title,
+ @RequestParam(name = "author", required = false) String author) {
+ List books = new ArrayList<>();
+ if (StringUtils.hasText(title)) {
+ bookRepository.findByTitle(title).forEach(books::add);
+ } else if (StringUtils.hasText(author)) {
+ bookRepository.findByAuthor(author).forEach(books::add);
+ } else {
+ bookRepository.findAll().forEach(books::add);
+ }
+
+ return ResponseEntity.ok(books);
+ }
+
+ @PostMapping
+ public ResponseEntity addBook(@RequestBody Book book) {
+ Book created = bookRepository.save(book);
+ return new ResponseEntity<>(created, HttpStatusCode.valueOf(201));
+ }
+
+ @PutMapping
+ public ResponseEntity updateBook(@RequestBody Book book) {
+ if (book.getId() < 1) {
+ return ResponseEntity.badRequest().build();
+ }
+ return addBook(bookRepository.save(book));
+ }
+
+ @DeleteMapping("/{id}")
+ public ResponseEntity> deleteBook(@PathVariable(name = "id") Long id) {
+ bookRepository.deleteById(id);
+ return ResponseEntity.noContent().build();
+ }
+}
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java
new file mode 100644
index 00000000..008343a2
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample;
+
+import com.oracle.nosql.spring.data.repository.NosqlRepository;
+
+public interface BookRepository extends NosqlRepository {
+ Iterable findByAuthor(String author);
+ Iterable findByTitle(String title);
+}
\ No newline at end of file
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java
new file mode 100644
index 00000000..ec6061df
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample;
+
+import com.oracle.nosql.spring.data.config.AbstractNosqlConfiguration;
+import com.oracle.nosql.spring.data.repository.config.EnableNosqlRepositories;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+@EnableNosqlRepositories
+public class SpringCloudOciNoSQLSampleApplication extends AbstractNosqlConfiguration {
+ public static void main(String[] args) {
+ SpringApplication.run(SpringCloudOciNoSQLSampleApplication.class, args);
+ }
+}
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml
new file mode 100644
index 00000000..a9f0eeb1
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml
@@ -0,0 +1,7 @@
+spring:
+ cloud:
+ oci:
+ config:
+ type: file
+ region:
+ static: us-ashburn-1
diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java
new file mode 100644
index 00000000..c62dbddc
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2024, Oracle and/or its affiliates.
+// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
+package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest
+public class NoSQLSampleApplicationIT {
+ @Autowired
+ private BookController bookController;
+
+ @Autowired
+ BookRepository bookRepository;
+
+ @Test
+ void bookControllerTest() {
+ // clear the book database before running the test
+ bookRepository.deleteAll();
+ // Create three Book objects
+ Book book1 = new Book();
+ book1.setTitle("To Kill a Mockingbird");
+ book1.setAuthor("Harper Lee");
+ book1.setPrice(12.99);
+
+ Book book2 = new Book();
+ book2.setTitle("1984");
+ book2.setAuthor("George Orwell");
+ book2.setPrice(10.99);
+
+ Book book3 = new Book();
+ book3.setTitle("Animal Farm");
+ book3.setAuthor("George Orwell"); // Same author as book2
+ book3.setPrice(9.99);
+
+ Book created1 = bookController.addBook(book1).getBody();
+ Book created2 = bookController.addBook(book2).getBody();
+ Book created3 = bookController.addBook(book3).getBody();
+
+ // Query books based on author
+ List georgeOrwellBooks = bookController.getAllBooks(null, "George Orwell").getBody();
+ assertThat(georgeOrwellBooks).hasSize(2);
+
+ // Query books based on title
+ List titleQueryBooks = bookController.getAllBooks("To Kill a Mockingbird", null).getBody();
+ assertThat(titleQueryBooks).hasSize(1);
+ assertThat(titleQueryBooks.get(0)).isEqualTo(created1);
+
+ // Update book
+ assertThat(created3).isNotNull();
+ created3.setPrice(25.00);
+ Book updated3 = bookController.updateBook(created3).getBody();
+ assertThat(updated3).isNotNull();
+ assertThat(updated3.getPrice()).isEqualTo(25.0);
+
+ // Delete book and verify it's gone
+ assertThat(created2).isNotNull();
+ bookController.deleteBook(created2.getId());
+ List title1984Books = bookController.getAllBooks("1984", null).getBody();
+ assertThat(title1984Books).hasSize(0);
+ }
+}
diff --git a/spring-cloud-oci/spring-cloud-oci-starters/pom.xml b/spring-cloud-oci/spring-cloud-oci-starters/pom.xml
index 03b6492f..527d88a8 100644
--- a/spring-cloud-oci/spring-cloud-oci-starters/pom.xml
+++ b/spring-cloud-oci/spring-cloud-oci-starters/pom.xml
@@ -59,6 +59,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
spring-cloud-oci-starter-queue
spring-cloud-oci-starter-function
spring-cloud-oci-starter-email
+ spring-cloud-oci-starter-nosql
\ No newline at end of file
diff --git a/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml b/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml
new file mode 100644
index 00000000..18387a3f
--- /dev/null
+++ b/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+
+ 4.0.0
+
+ spring-cloud-oci-starters
+ com.oracle.cloud.spring
+ 1.3.0-SNAPSHOT
+
+
+ spring-cloud-oci-starter-nosql
+ Spring Cloud Oracle NoSQL Starter Module
+ Spring Cloud Oracle NoSQL Starter Module
+ https://github.com/oracle/spring-cloud-oci/#spring-cloud-oci-documentation
+
+
+ Oracle America, Inc.
+ https://www.oracle.com
+
+
+
+
+ Oracle
+ obaas_ww at oracle.com
+ Oracle America, Inc.
+ https://www.oracle.com
+
+
+
+
+
+ The Universal Permissive License (UPL), Version 1.0
+ https://oss.oracle.com/licenses/upl/
+ repo
+
+
+
+
+ https://github.com/oracle/spring-cloud-oracle
+ scm:git:https://github.com/oracle/spring-cloud-oracle.git
+ scm:git:git@github.com:oracle/spring-cloud-oracle.git
+
+
+
+
+ com.oracle.cloud.spring
+ spring-cloud-oci-starter
+
+
+ com.oracle.nosql.sdk
+ spring-data-oracle-nosql
+
+
+
+