details;
+ boolean enabled;
+}
diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java
new file mode 100644
index 00000000..9e27babb
--- /dev/null
+++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java
@@ -0,0 +1,15 @@
+package com.dtsx.astra.sdk.pcu.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class PCUTypeLocationFilter {
+ String provider;
+ String region;
+}
diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java
new file mode 100644
index 00000000..e393c61e
--- /dev/null
+++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java
@@ -0,0 +1,58 @@
+package com.dtsx.astra.sdk.pcu.domain;
+
+import java.util.List;
+
+/**
+ * Utility class for resolving default PCU types based on availability and configuration.
+ */
+public class PCUTypeResolver {
+
+ /**
+ * Resolves the default PCU type based on available types and mini PCU configuration.
+ *
+ * Selection priority when mini PCU is enabled:
+ * SMALL > MEDIUM > GENERAL_PURPOSE > CACHE_OPTIMIZED
+ *
+ *
Selection priority when mini PCU is disabled:
+ * GENERAL_PURPOSE > CACHE_OPTIMIZED (SMALL and MEDIUM are ignored)
+ *
+ * @param availableTypes list of available PCU family types
+ * @param miniPcuEnabled whether mini PCU is enabled
+ * @return the selected PCU family, or null if no suitable type is available
+ */
+ public static PCUInstanceType resolveDefaultPcuType(List availableTypes, boolean miniPcuEnabled) {
+ if (availableTypes == null || availableTypes.isEmpty()) {
+ return null;
+ }
+
+ if (miniPcuEnabled) {
+ // Priority: SMALL > MEDIUM > GENERAL_PURPOSE > CACHE_OPTIMIZED
+ if (availableTypes.contains(PCUInstanceType.small)) {
+ return PCUInstanceType.small;
+ }
+ if (availableTypes.contains(PCUInstanceType.medium)) {
+ return PCUInstanceType.medium;
+ }
+ if (availableTypes.contains(PCUInstanceType.generalPurpose)) {
+ return PCUInstanceType.generalPurpose;
+ }
+ if (availableTypes.contains(PCUInstanceType.cacheOptimized)) {
+ return PCUInstanceType.cacheOptimized;
+ }
+ } else {
+ // Priority: GENERAL_PURPOSE > CACHE_OPTIMIZED (ignore SMALL and MEDIUM)
+ if (availableTypes.contains(PCUInstanceType.generalPurpose)) {
+ return PCUInstanceType.generalPurpose;
+ }
+ if (availableTypes.contains(PCUInstanceType.cacheOptimized)) {
+ return PCUInstanceType.cacheOptimized;
+ }
+ }
+
+ return null;
+ }
+
+ private PCUTypeResolver() {
+ // Utility class - prevent instantiation
+ }
+}
diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java
deleted file mode 100644
index 0e6d47e8..00000000
--- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.dtsx.astra.sdk.pcu.domain;
-
-import com.dtsx.astra.sdk.db.domain.CloudProviderType;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * Represents a PCU (Processing Capacity Units) Group in Astra.
- * A PCU group manages compute resources for databases across cloud providers and regions.
- */
-@Data
-@NoArgsConstructor
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class PcuGroup {
- /**
- * Unique identifier for the PCU group.
- */
- @JsonProperty("uuid")
- private String id;
-
- /**
- * Organization identifier.
- */
- private String orgId;
-
- /**
- * Human-readable title for the PCU group.
- */
- private String title;
-
- /**
- * Description of the PCU group.
- */
- private String description;
-
- /**
- * Cloud provider where the PCU group is deployed.
- */
- private CloudProviderType cloudProvider;
-
- /**
- * Cloud region where the PCU group is deployed.
- */
- private String region;
-
- /**
- * Instance type for the PCU group.
- */
- private String instanceType;
-
- /**
- * Provisioning type (e.g., on-demand, reserved).
- */
- private PcuProvisionType provisionType;
-
- /**
- * Minimum number of PCUs.
- */
- private int min;
-
- /**
- * Maximum number of PCUs.
- */
- private int max;
-
- /**
- * Number of reserved PCUs.
- */
- private int reserved;
-
- /**
- * Timestamp when the PCU group was created.
- */
- private String createdAt;
-
- /**
- * Timestamp when the PCU group was last updated.
- */
- private String updatedAt;
-
- /**
- * User who created the PCU group.
- */
- private String createdBy;
-
- /**
- * User who last updated the PCU group.
- */
- private String updatedBy;
-
- /**
- * Current status of the PCU group.
- */
- private PcuGroupStatusType status;
-}
diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java
index 8f0fbfb4..ee1833b4 100644
--- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java
+++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java
@@ -2,6 +2,8 @@
import lombok.Getter;
+import java.util.UUID;
+
/**
* Exception thrown when a datacenter association with a PCU (Processing Capacity Units) Group cannot be found.
* This occurs when attempting to access or modify an association that doesn't exist.
@@ -11,7 +13,7 @@ public class PcuGroupDbAssociationNotFound extends RuntimeException {
* PCU group unique identifier.
*/
@Getter
- private final String pcuGroupId;
+ private final UUID pcuGroupId;
/**
* Datacenter unique identifier.
@@ -27,7 +29,7 @@ public class PcuGroupDbAssociationNotFound extends RuntimeException {
* @param datacenterId
* the datacenter ID
*/
- public PcuGroupDbAssociationNotFound(String pcuGroupId, String datacenterId) {
+ public PcuGroupDbAssociationNotFound(UUID pcuGroupId, String datacenterId) {
super("Association not found for pcu group '" + pcuGroupId + "' and datacenter '" + datacenterId + "'");
this.pcuGroupId = pcuGroupId;
this.datacenterId = datacenterId;
diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java
index 920d3e4c..04ccb451 100644
--- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java
+++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java
@@ -3,6 +3,7 @@
import lombok.Getter;
import java.util.Optional;
+import java.util.UUID;
/**
* Exception thrown when a PCU (Processing Capacity Units) Group cannot be found.
@@ -20,7 +21,7 @@ public class PcuGroupNotFoundException extends RuntimeException {
* Optional ID of the PCU group that was not found.
*/
@Getter
- private final Optional id;
+ private final Optional id;
/**
* Private constructor for creating the exception.
@@ -30,12 +31,28 @@ public class PcuGroupNotFoundException extends RuntimeException {
* @param id
* optional ID of the PCU group
*/
- private PcuGroupNotFoundException(Optional title, Optional id) {
- super("PCU group " + title.or(() -> id).map(s -> "'" + s + "' ").orElse("") + "has not been found.");
+ private PcuGroupNotFoundException(Optional title, Optional id) {
+ super(buildErrorMessage(title, id));
this.title = title;
this.id = id;
}
+ /**
+ * Build Error Message.
+ * @param title
+ * title
+ * @param id
+ * PUC group identifier
+ * @return
+ * exception
+ */
+ private static String buildErrorMessage(Optional title, Optional id) {
+ String identifier = title
+ .map(t -> "'" + t + "'")
+ .orElseGet(() -> id.map(uuid -> "'" + uuid + "'").orElse(""));
+ return "PCU group " + identifier + " has not been found.";
+ }
+
/**
* Creates an exception for a PCU group not found by title.
*
@@ -56,7 +73,7 @@ public static PcuGroupNotFoundException forTitle(String title) {
* @return
* exception instance
*/
- public static PcuGroupNotFoundException forId(String id) {
+ public static PcuGroupNotFoundException forId(UUID id) {
return new PcuGroupNotFoundException(Optional.empty(), Optional.of(id));
}
}
diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java
index 64607136..4dcccfd7 100644
--- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java
+++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java
@@ -4,6 +4,7 @@
import com.dtsx.astra.sdk.db.AstraDBOpsClient;
import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest;
import com.dtsx.astra.sdk.streaming.AstraStreamingClient;
+import com.dtsx.astra.sdk.utils.AstraEnvironment;
import com.dtsx.astra.sdk.utils.AstraRc;
import com.dtsx.astra.sdk.utils.Utils;
import org.junit.jupiter.api.Assertions;
@@ -33,25 +34,30 @@ public abstract class AbstractDevopsApiTest {
*/
private static String token;
+ /**
+ * Hold reference to token
+ */
+ private static AstraEnvironment env;
+
/**
* Reference to Databases Client.
*/
- private static AstraDBOpsClient databasesClient;
+ protected static AstraDBOpsClient databasesClient;
/**
* Reference to organization client.
*/
- private static AstraOpsClient apiDevopsClient;
+ protected static AstraOpsClient apiDevopsClient;
/**
* Working db.
*/
- private static DbOpsClient dbClient;
+ protected static DbOpsClient dbClient;
/**
* Reference to Databases Client.
*/
- private static AstraStreamingClient streamingClient;
+ protected static AstraStreamingClient streamingClient;
/**
* Access DB client.
@@ -61,7 +67,7 @@ public abstract class AbstractDevopsApiTest {
*/
protected AstraOpsClient getApiDevopsClient() {
if (apiDevopsClient == null) {
- apiDevopsClient = new AstraOpsClient(getToken());
+ apiDevopsClient = new AstraOpsClient(getToken(), getEnvironment());
}
return apiDevopsClient;
}
@@ -74,7 +80,7 @@ protected AstraOpsClient getApiDevopsClient() {
*/
protected AstraDBOpsClient getDatabasesClient() {
if (databasesClient == null) {
- databasesClient = new AstraDBOpsClient(getToken());
+ databasesClient = new AstraDBOpsClient(getToken(), getEnvironment());
}
return databasesClient;
}
@@ -87,7 +93,7 @@ protected AstraDBOpsClient getDatabasesClient() {
*/
protected AstraStreamingClient getStreamingClient() {
if (streamingClient == null) {
- streamingClient = new AstraStreamingClient(getToken());
+ streamingClient = new AstraStreamingClient(getToken(), getEnvironment());
}
return streamingClient;
}
@@ -110,6 +116,21 @@ protected String getToken() {
return token;
}
+ protected AstraEnvironment getEnvironment() {
+ String envStr = null;
+ if (env == null) {
+ if (AstraRc.isDefaultConfigFileExists()) {
+ envStr = new AstraRc()
+ .getSectionKey(AstraRc.ASTRARC_DEFAULT, AstraRc.ASTRA_ENV)
+ .orElse(null);
+ env = AstraEnvironment.valueOf(envStr);
+ }
+ envStr = Utils.readEnvVariable(AstraRc.ASTRA_ENV).orElse(envStr);
+ env = AstraEnvironment.valueOf(envStr);
+ }
+ return env;
+ }
+
/**
* Create DB if not exist
*
diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java
new file mode 100644
index 00000000..9e9ddcf1
--- /dev/null
+++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java
@@ -0,0 +1,187 @@
+package com.dtsx.astra.sdk.pcu;
+
+import com.dtsx.astra.sdk.AbstractDevopsApiTest;
+import com.dtsx.astra.sdk.AstraOpsClient;
+import com.dtsx.astra.sdk.db.domain.CloudProviderType;
+import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest;
+import com.dtsx.astra.sdk.db.domain.DatabaseStatusType;
+import com.dtsx.astra.sdk.org.domain.Organization;
+import com.dtsx.astra.sdk.pcu.domain.PCUCapacityWorkloadType;
+import com.dtsx.astra.sdk.pcu.domain.PCUGroup;
+import com.dtsx.astra.sdk.pcu.domain.PCUGroupCreationRequest;
+import com.dtsx.astra.sdk.pcu.domain.PCUInstanceType;
+import com.dtsx.astra.sdk.pcu.domain.PCUProvisionType;
+import com.dtsx.astra.sdk.pcu.domain.PCUType;
+import com.dtsx.astra.sdk.pcu.domain.PCUTypeLocationFilter;
+import com.dtsx.astra.sdk.utils.AstraEnvironment;
+import com.dtsx.astra.sdk.utils.JsonUtils;
+import com.dtsx.astra.sdk.utils.TestUtils;
+import com.dtsx.astra.sdk.utils.Utils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+// Unpredictable so re;oving fro; automated tests
+//@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class PCUGroupClientDevTest extends AbstractDevopsApiTest {
+
+ public static final String DEV_REGION = "us-west-2";
+ public static final CloudProviderType DEV_PROVIDER = CloudProviderType.AWS;
+
+ public static final String DEV_TOKEN = Utils
+ .readEnvVariable("ASTRA_DB_APPLICATION_TOKEN_DEV")
+ .orElseThrow(() -> new IllegalStateException("Please set env var 'ASTRA_DB_APPLICATION_TOKEN_DEV' with a dev token"));
+
+ protected static PCUGroupsOpsClient PCUGroupsOpsClient;
+
+ @BeforeAll
+ public static void beforeAll() {
+ apiDevopsClient = new AstraOpsClient(DEV_TOKEN, AstraEnvironment.DEV);
+ PCUGroupsOpsClient = apiDevopsClient.pcus();
+ }
+
+ @Test
+ @Order(1)
+ public void shouldAccessOrganizationInDev() {
+ Organization org = getApiDevopsClient().getOrganization();
+ Assertions.assertNotNull(org);
+ Assertions.assertNotNull(org.getId());
+ Assertions.assertNotNull(org.getName());
+ System.out.println("[test-pcu] - You are connected to organization: " + org.getName() + "(" + org.getId() + ")");
+ }
+
+ @Test
+ @Order(2)
+ public void shouldListPcuGroupsType() {
+ // Full List
+ System.out.println("[test-pcu] - Listing PCU Types (no filters)");
+ Stream types = PCUGroupsOpsClient.listPcuTypes();
+ System.out.println("[test-pcu] - Items " + types.toList().size());
+
+ // Filtered by DC
+ PCUTypeLocationFilter location = new PCUTypeLocationFilter(DEV_PROVIDER.getCode().toLowerCase(), DEV_REGION);
+ System.out.println("[test-pcu] - Listing PCU Types on " + JsonUtils.marshall(location));
+ List filtered = getApiDevopsClient().pcus().listPcuTypes(location).toList();
+ Assertions.assertNotNull(filtered);
+ System.out.println("[test-pcu] - Items " + filtered.size());
+ System.out.println("[test-pcu] - Items " + JsonUtils.marshall(filtered));
+ Assertions.assertTrue(filtered.stream().anyMatch(pcu -> pcu.getType().equals("small")));
+ }
+
+ @Test
+ @Order(2)
+ public void shouldListPcuGroups() {
+ List allGroups = PCUGroupsOpsClient.findAll().toList();
+ System.out.println("[test-pcu] - Listing pcu groups " + JsonUtils.marshall(allGroups));
+ System.out.println("[test-pcu] - Items " + allGroups.size());
+ }
+
+ @Test
+ @Order(3)
+ public void shouldCreatePcuGroupStandard() {
+
+ UUID pcuGroupStandardId = null;
+ try {
+ PCUGroupCreationRequest createPcu = PCUGroupCreationRequest
+ .builder()
+ .title("pcu_group_from_java")
+ .description("my first PCU group")
+ .instanceType("standard")
+ .cloudProvider(CloudProviderType.AWS)
+ .region(DEV_REGION)
+ .workloadType(PCUCapacityWorkloadType.flexible.name())
+ .provisionType(PCUProvisionType.shared.name())
+ .reserved(1)
+ .min(1)
+ .max(1)
+ .build();
+
+ // Creating standard pcu Group
+ PCUGroup group = PCUGroupsOpsClient.create(createPcu);
+ Assertions.assertNotNull(group);
+ pcuGroupStandardId = pcuGroupStandardId = group.getId();
+ System.out.println("[test-pcu] - Created PCU group: " + group.getId());
+ Assertions.assertTrue(getApiDevopsClient().pcus().findById(group.getId()).isPresent());
+
+ // Create DB
+ DatabaseCreationRequest dbCreation = DatabaseCreationRequest
+ .builder()
+ .name("vector_db_in_standard_pcu")
+ .keyspace(SDK_TEST_KEYSPACE)
+ .cloudProvider(CloudProviderType.AWS)
+ .cloudRegion(DEV_REGION)
+ .withVector()
+ .assignToPCUGroup(pcuGroupStandardId)
+ .build();
+
+ String dbId = getApiDevopsClient().db().create(dbCreation);
+ TestUtils.waitForDbStatus(getDatabasesClient().database(dbId), DatabaseStatusType.ACTIVE, 500);
+ Assertions.assertTrue(getDatabasesClient().findById(dbId).isPresent());
+ Assertions.assertNotNull(getDatabasesClient().database(dbId).get());
+ Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_standard_pcu").findAny().isPresent());
+
+ } catch (RuntimeException e) {
+
+ } finally {
+ if (pcuGroupStandardId != null) {
+ PCUGroupsOpsClient.group(pcuGroupStandardId).delete();
+ }
+ }
+ }
+
+ @Test
+ @Order(2)
+ public void shouldCreateMiniPcu() {
+ PCUGroupCreationRequest createPcu = PCUGroupCreationRequest
+ .builder()
+ .title("java_client_mini_pcu")
+ .description("java_client_mini_pcu")
+ .instanceType(PCUInstanceType.small.name())
+ .cloudProvider(CloudProviderType.AWS)
+ .region(DEV_REGION)
+ .workloadType(PCUCapacityWorkloadType.flexible.name())
+ .provisionType(PCUProvisionType.shared.name())
+ .reserved(1)
+ .min(1)
+ .max(1)
+ .build();
+ PCUGroup group = getApiDevopsClient().pcus().create(createPcu);
+ System.out.println(group);
+ }
+
+ @Test
+ @Order(2)
+ public void shouldDeletePcuGroup() {
+ PCUGroupsOpsClient.group(UUID.fromString("0c1f67a8-1fd6-4f52-ae2c-ea1483718a11")).delete();
+ }
+
+ @Test
+ @Order(3)
+ public void should_create_db_and_assign_pcu() throws InterruptedException {
+ UUID miniPcuUUID = UUID.fromString("57dde257-86c6-4646-9247-670cd8a4d360");
+ DatabaseCreationRequest dbCreation = DatabaseCreationRequest
+ .builder()
+ .name("vector_db_in_mini_pcu")
+ .keyspace(SDK_TEST_KEYSPACE)
+ .cloudProvider(CloudProviderType.AWS)
+ .cloudRegion(DEV_REGION)
+ .withVector()
+ .assignToPCUGroup(miniPcuUUID)
+ .build();
+ String dbId = getApiDevopsClient().db().create(dbCreation);
+ Thread.sleep(10000);
+ Assertions.assertTrue(getDatabasesClient().findById(dbId).isPresent());
+ Assertions.assertNotNull(getDatabasesClient().database(dbId).get());
+ Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_mini_pcu").count() > 0);
+ // When
+ TestUtils.waitForDbStatus(getDatabasesClient().database(dbId), DatabaseStatusType.ACTIVE, 500);
+ }
+
+}
diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java
new file mode 100644
index 00000000..ab38ecc9
--- /dev/null
+++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java
@@ -0,0 +1,132 @@
+package com.dtsx.astra.sdk.pcu;
+
+import com.dtsx.astra.sdk.pcu.domain.PCUInstanceType;
+import com.dtsx.astra.sdk.pcu.domain.PCUTypeResolver;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Test class for PcuTypeResolver.
+ */
+@DisplayName("PcuTypeResolver Tests")
+class PCUTypeResolverTest {
+
+ @Nested
+ @DisplayName("Mini PCU Enabled")
+ class MiniPcuEnabled {
+
+ @Test
+ @DisplayName("Selects SMALL when SMALL is available")
+ void selectsSmallWhenSmallIsAvailable() {
+ List availableTypes = Arrays.asList(
+ PCUInstanceType.small,
+ PCUInstanceType.medium,
+ PCUInstanceType.generalPurpose,
+ PCUInstanceType.cacheOptimized
+ );
+
+ assertEquals(
+ PCUInstanceType.small,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, true)
+ );
+ }
+
+ @Test
+ @DisplayName("Selects MEDIUM when SMALL is unavailable but MEDIUM exists")
+ void selectsMediumWhenSmallUnavailableButMediumExists() {
+ List availableTypes = Arrays.asList(
+ PCUInstanceType.medium,
+ PCUInstanceType.generalPurpose
+ );
+
+ assertEquals(
+ PCUInstanceType.medium,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, true)
+ );
+ }
+
+ @Test
+ @DisplayName("Selects GENERAL_PURPOSE when only GENERAL_PURPOSE and CACHE_OPTIMIZED exist")
+ void selectsGeneralPurposeWhenOnlyGeneralPurposeAndCacheOptimizedExist() {
+ List availableTypes = Arrays.asList(
+ PCUInstanceType.generalPurpose,
+ PCUInstanceType.cacheOptimized
+ );
+
+ assertEquals(
+ PCUInstanceType.generalPurpose,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, true)
+ );
+ }
+
+ @Test
+ @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type")
+ void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() {
+ List availableTypes = Collections.singletonList(
+ PCUInstanceType.cacheOptimized
+ );
+
+ assertEquals(
+ PCUInstanceType.cacheOptimized,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, true)
+ );
+ }
+
+ @Test
+ @DisplayName("Returns null when no types are available")
+ void returnsNullWhenNoTypesAreAvailable() {
+ assertNull(PCUTypeResolver.resolveDefaultPcuType(Collections.emptyList(), true));
+ }
+ }
+
+ @Nested
+ @DisplayName("Mini PCU Disabled")
+ class MiniPcuDisabled {
+
+ @Test
+ @DisplayName("Selects GENERAL_PURPOSE when GENERAL_PURPOSE is available")
+ void selectsGeneralPurposeWhenGeneralPurposeIsAvailable() {
+ List availableTypes = Arrays.asList(
+ PCUInstanceType.generalPurpose,
+ PCUInstanceType.cacheOptimized
+ );
+
+ assertEquals(
+ PCUInstanceType.generalPurpose,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, false)
+ );
+ }
+
+ @Test
+ @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type")
+ void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() {
+ List availableTypes = Collections.singletonList(
+ PCUInstanceType.cacheOptimized
+ );
+
+ assertEquals(
+ PCUInstanceType.cacheOptimized,
+ PCUTypeResolver.resolveDefaultPcuType(availableTypes, false)
+ );
+ }
+
+ @Test
+ @DisplayName("Returns null when only SMALL or MEDIUM are available")
+ void returnsNullWhenOnlySmallOrMediumAreAvailable() {
+ List availableTypes = Arrays.asList(
+ PCUInstanceType.small,
+ PCUInstanceType.medium
+ );
+
+ assertNull(PCUTypeResolver.resolveDefaultPcuType(availableTypes, false));
+ }
+ }
+}
diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java
deleted file mode 100644
index 0d1b53e4..00000000
--- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.dtsx.astra.sdk.pcu;
-
-import com.dtsx.astra.sdk.AstraOpsClient;
-import com.dtsx.astra.sdk.utils.AstraEnvironment;
-import lombok.val;
-import org.junit.jupiter.api.Test;
-
-public class ParkingTest {
-
-}
diff --git a/integrations/skills/spring-boot-data-api/README.md b/integrations/skills/spring-boot-data-api/README.md
index a290b4a0..04fc6257 100644
--- a/integrations/skills/spring-boot-data-api/README.md
+++ b/integrations/skills/spring-boot-data-api/README.md
@@ -5,8 +5,8 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli
## Quick Links
- π **[Main Skill Document](SKILL.md)** - Complete step-by-step guide
-- π **[Code Templates](templates/)** - Reusable code templates
-- π‘ **[Basic Example](examples/basic/)** - Minimal working example
+- π **[Code Templates](assets/templates/)** - Reusable code templates
+- π‘ **[Basic Example](assets/examples/basic/)** - Minimal working example
## What You'll Learn
@@ -29,6 +29,26 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli
30-45 minutes
+## Folder Structure
+
+```
+spring-boot-data-api/
+βββ README.md # This file
+βββ SKILL.md # Main skill guide
+βββ references/ # Additional reference docs (future)
+βββ scripts/ # Automation scripts (future)
+βββ assets/ # Reusable assets
+ βββ templates/ # Code templates
+ β βββ Document.java.template
+ β βββ Repository.java.template
+ β βββ Service.java.template
+ β βββ Controller.java.template
+ β βββ application.yml.template
+ βββ examples/ # Working examples
+ βββ basic/ # Basic example
+ βββ README.md
+```
+
## How to Use This Skill
### With Claude
@@ -70,7 +90,7 @@ integrations/skills/spring-boot-data-api/SKILL.md
```
2. **Use templates to generate code:**
- - Copy templates from `templates/` directory
+ - Copy templates from `assets/templates/` directory
- Replace placeholders ({{CLASS_NAME}}, {{COLLECTION_NAME}}, etc.)
- Customize for your use case
diff --git a/integrations/skills/spring-boot-data-api/examples/basic/README.md b/integrations/skills/spring-boot-data-api/examples/basic/README.md
deleted file mode 100644
index 99b6a409..00000000
--- a/integrations/skills/spring-boot-data-api/examples/basic/README.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Basic Spring Boot with Astra DB Example
-
-This is a minimal working example demonstrating Spring Boot integration with Astra DB.
-
-## What's Included
-
-- Simple Product entity with basic CRUD operations
-- Spring Data repository
-- REST API endpoints
-- Configuration examples
-
-## Quick Start
-
-1. **Set environment variables:**
- ```bash
- export ASTRA_DB_TOKEN="AstraCS:..."
- export ASTRA_DB_ENDPOINT="https://your-db-id-region.apps.astra.datastax.com"
- ```
-
-2. **Run the application:**
- ```bash
- mvn spring-boot:run
- ```
-
-3. **Test the API:**
- ```bash
- # Create a product
- curl -X POST http://localhost:8080/api/products \
- -H "Content-Type: application/json" \
- -d '{"name":"Laptop","category":"Electronics","price":999.99,"stock":10}'
-
- # List all products
- curl http://localhost:8080/api/products
-
- # Get by ID
- curl http://localhost:8080/api/products/{id}
- ```
-
-## Project Structure
-
-```
-src/
-βββ main/
-β βββ java/
-β β βββ com/example/demo/
-β β βββ DemoApplication.java
-β β βββ model/
-β β β βββ Product.java
-β β βββ repository/
-β β β βββ ProductRepository.java
-β β βββ service/
-β β β βββ ProductService.java
-β β βββ controller/
-β β βββ ProductController.java
-β βββ resources/
-β βββ application.yml
-βββ test/
- βββ java/
- βββ com/example/demo/
- βββ ProductServiceTest.java
-```
-
-## Next Steps
-
-- Add vector search capabilities
-- Implement pagination
-- Add validation
-- Create integration tests
-- Deploy to production
-
-See the main [SKILL.md](../../SKILL.md) for detailed guidance.
diff --git a/integrations/skills/spring-boot-data-api/templates/Controller.java.template b/integrations/skills/spring-boot-data-api/templates/Controller.java.template
deleted file mode 100644
index 20311ef0..00000000
--- a/integrations/skills/spring-boot-data-api/templates/Controller.java.template
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.example.demo.controller;
-
-import com.example.demo.model.{{CLASS_NAME}};
-import com.example.demo.service.{{CLASS_NAME}}Service;
-import jakarta.validation.Valid;
-import lombok.RequiredArgsConstructor;
-import org.springframework.data.domain.Page;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-
-/**
- * REST controller for {{CLASS_NAME}} endpoints.
- */
-@RestController
-@RequestMapping("/api/{{RESOURCE_PATH}}")
-@RequiredArgsConstructor
-public class {{CLASS_NAME}}Controller {
-
- private final {{CLASS_NAME}}Service service;
-
- /**
- * List all entities.
- */
- @GetMapping
- public List<{{CLASS_NAME}}> list() {
- return service.findAll();
- }
-
- /**
- * List entities with pagination.
- */
- @GetMapping("/paginated")
- public Page<{{CLASS_NAME}}> listPaginated(
- @RequestParam(defaultValue = "0") int page,
- @RequestParam(defaultValue = "20") int size,
- @RequestParam(defaultValue = "id") String sortBy) {
- return service.findAllPaginated(page, size, sortBy);
- }
-
- /**
- * Get entity by ID.
- */
- @GetMapping("/{id}")
- public {{CLASS_NAME}} get(@PathVariable String id) {
- return service.findById(id)
- .orElseThrow(() -> new ResourceNotFoundException("Entity not found"));
- }
-
- /**
- * Create new entity.
- */
- @PostMapping
- @ResponseStatus(HttpStatus.CREATED)
- public {{CLASS_NAME}} create(@Valid @RequestBody {{CLASS_NAME}} entity) {
- return service.create(entity);
- }
-
- /**
- * Update existing entity.
- */
- @PutMapping("/{id}")
- public {{CLASS_NAME}} update(
- @PathVariable String id,
- @Valid @RequestBody {{CLASS_NAME}} entity) {
- return service.update(id, entity);
- }
-
- /**
- * Delete entity.
- */
- @DeleteMapping("/{id}")
- @ResponseStatus(HttpStatus.NO_CONTENT)
- public void delete(@PathVariable String id) {
- service.delete(id);
- }
-
- /**
- * Search entities.
- */
- @GetMapping("/search")
- public List<{{CLASS_NAME}}> search(
- @RequestParam String field,
- @RequestParam String value) {
- return service.search(field, value);
- }
-}
-
-class ResourceNotFoundException extends RuntimeException {
- public ResourceNotFoundException(String message) {
- super(message);
- }
-}
diff --git a/integrations/skills/spring-boot-data-api/templates/Document.java.template b/integrations/skills/spring-boot-data-api/templates/Document.java.template
deleted file mode 100644
index 1ce2b922..00000000
--- a/integrations/skills/spring-boot-data-api/templates/Document.java.template
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.example.demo.model;
-
-import com.datastax.astra.client.collections.mapping.*;
-import com.datastax.astra.client.core.vector.SimilarityMetric;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import jakarta.validation.constraints.*;
-import lombok.Data;
-import lombok.experimental.Accessors;
-
-import java.time.Instant;
-
-/**
- * Document class template for Astra DB collections.
- *
- * Replace {{COLLECTION_NAME}} with your collection name.
- * Customize fields, validation, and indexing as needed.
- */
-@Data
-@Accessors(chain = true)
-@DataApiCollection(
- name = "{{COLLECTION_NAME}}",
- // Optional: Vector search configuration
- // vectorDimension = 1536,
- // vectorSimilarity = SimilarityMetric.COSINE,
- // vectorizeProvider = "openai",
- // vectorizeModel = "text-embedding-ada-002",
- // vectorizeSharedSecret = "OPENAI_API_KEY",
-
- // Optional: Full-text search
- // lexicalEnabled = true,
- // lexicalAnalyzer = AnalyzerTypes.ENGLISH,
-
- // Optional: Indexing optimization
- indexingDeny = {"internal_field"}
-)
-public class {{CLASS_NAME}} {
-
- @DocumentId
- private String id;
-
- @NotBlank(message = "Field is required")
- private String field1;
-
- @NotNull(message = "Field is required")
- private String field2;
-
- // Optional: Auto-vectorization
- // @Vectorize
- // private String vectorizeField;
-
- // Optional: Full-text search
- // @Lexical
- // private String searchableText;
-
- @JsonProperty("created_at")
- private Instant createdAt;
-
- @JsonProperty("updated_at")
- private Instant updatedAt;
-}
diff --git a/integrations/skills/spring-boot-data-api/templates/Repository.java.template b/integrations/skills/spring-boot-data-api/templates/Repository.java.template
deleted file mode 100644
index 58571d21..00000000
--- a/integrations/skills/spring-boot-data-api/templates/Repository.java.template
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.example.demo.repository;
-
-import com.datastax.astra.spring.DataApiCollectionCrudRepository;
-import com.example.demo.model.{{CLASS_NAME}};
-import org.springframework.stereotype.Repository;
-
-/**
- * Spring Data repository for {{CLASS_NAME}}.
- *
- * Provides CRUD operations and query capabilities:
- * - save(entity)
- * - findById(id)
- * - findAll()
- * - deleteById(id)
- * - count()
- * - Query by Example
- * - Data API filters
- */
-@Repository
-public interface {{CLASS_NAME}}Repository
- extends DataApiCollectionCrudRepository<{{CLASS_NAME}}, String> {
-
- // Custom query methods can be added here
- // Spring Data will automatically implement them
-}
diff --git a/integrations/skills/spring-boot-data-api/templates/Service.java.template b/integrations/skills/spring-boot-data-api/templates/Service.java.template
deleted file mode 100644
index c565884c..00000000
--- a/integrations/skills/spring-boot-data-api/templates/Service.java.template
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.example.demo.service;
-
-import com.datastax.astra.client.core.query.Filter;
-import com.datastax.astra.client.core.query.Filters;
-import com.example.demo.model.{{CLASS_NAME}};
-import com.example.demo.repository.{{CLASS_NAME}}Repository;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.data.domain.*;
-import org.springframework.stereotype.Service;
-
-import java.time.Instant;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * Service layer for {{CLASS_NAME}} business logic.
- */
-@Slf4j
-@Service
-@RequiredArgsConstructor
-public class {{CLASS_NAME}}Service {
-
- private final {{CLASS_NAME}}Repository repository;
-
- /**
- * Create a new entity.
- */
- public {{CLASS_NAME}} create({{CLASS_NAME}} entity) {
- entity.setCreatedAt(Instant.now());
- entity.setUpdatedAt(Instant.now());
- log.info("Creating entity: {}", entity);
- return repository.save(entity);
- }
-
- /**
- * Find entity by ID.
- */
- public Optional<{{CLASS_NAME}}> findById(String id) {
- return repository.findById(id);
- }
-
- /**
- * Find all entities.
- */
- public List<{{CLASS_NAME}}> findAll() {
- return (List<{{CLASS_NAME}}>) repository.findAll();
- }
-
- /**
- * Update an existing entity.
- */
- public {{CLASS_NAME}} update(String id, {{CLASS_NAME}} updates) {
- {{CLASS_NAME}} entity = repository.findById(id)
- .orElseThrow(() -> new ResourceNotFoundException("Entity not found: " + id));
-
- // Update fields
- // entity.setField1(updates.getField1());
- // entity.setField2(updates.getField2());
- entity.setUpdatedAt(Instant.now());
-
- return repository.save(entity);
- }
-
- /**
- * Delete entity by ID.
- */
- public void delete(String id) {
- repository.deleteById(id);
- }
-
- /**
- * Find entities with pagination.
- */
- public Page<{{CLASS_NAME}}> findAllPaginated(int page, int size, String sortBy) {
- Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
- return repository.findAll(Example.of(new {{CLASS_NAME}}()), pageable);
- }
-
- /**
- * Search entities using Data API filters.
- */
- public List<{{CLASS_NAME}}> search(String field, String value) {
- Filter filter = Filters.eq(field, value);
- return (List<{{CLASS_NAME}}>) repository.findAll(filter);
- }
-}
-
-class ResourceNotFoundException extends RuntimeException {
- public ResourceNotFoundException(String message) {
- super(message);
- }
-}
diff --git a/integrations/skills/spring-boot-data-api/templates/application.yml.template b/integrations/skills/spring-boot-data-api/templates/application.yml.template
deleted file mode 100644
index af5b7500..00000000
--- a/integrations/skills/spring-boot-data-api/templates/application.yml.template
+++ /dev/null
@@ -1,63 +0,0 @@
-# Spring Boot Application Configuration for Astra DB
-
-spring:
- application:
- name: {{APPLICATION_NAME}}
-
-astra:
- data-api:
- # Database connection (required)
- token: ${ASTRA_DB_TOKEN}
- endpoint-url: ${ASTRA_DB_ENDPOINT}
- keyspace: ${ASTRA_DB_KEYSPACE:default_keyspace}
-
- # Schema management
- # Options: CREATE_IF_NOT_EXISTS, VALIDATE, NONE
- schema-action: CREATE_IF_NOT_EXISTS
-
- # Request logging (development)
- log-request: ${ASTRA_LOG_REQUESTS:false}
-
- # Advanced options
- options:
- # Timeouts (milliseconds)
- timeout:
- connect: 5000
- request: 10000
- general: 30000
- collection-admin: 60000
-
- # HTTP configuration
- http:
- retry-count: 3
- retry-delay: 100
- version: HTTP_2
- redirect: NORMAL
-
- # Embedding API key for vector search (optional)
- embedding-api-key: ${OPENAI_API_KEY:}
-
-# Logging configuration
-logging:
- level:
- root: INFO
- com.example.demo: DEBUG
- com.datastax.astra: ${ASTRA_LOG_LEVEL:INFO}
- com.datastax.astra.client.DataAPIClient: ${ASTRA_LOG_LEVEL:INFO}
-
-# Server configuration
-server:
- port: ${PORT:8080}
- error:
- include-message: always
- include-binding-errors: always
-
-# Actuator endpoints (optional)
-management:
- endpoints:
- web:
- exposure:
- include: health,info,metrics
- metrics:
- tags:
- application: ${spring.application.name}
diff --git a/pom.xml b/pom.xml
index c073b457..895ee433 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,9 +22,9 @@
UTF-8
- 2.0.17
- 1.5.32
- 2.21.3
+ 2.0.18
+ 1.5.37
+ 2.22.0
1.18.46
0.15.0
4.3.0
@@ -32,8 +32,8 @@
5.2.0
- 1.14.0
- 1.14.0-beta24
+ 1.17.0
+ 1.17.0-beta27
true