Skip to content

Conversation

sandsinh
Copy link
Contributor

@sandsinh sandsinh commented Oct 1, 2025

🎯 Purpose

Implements a many-to-many relationship between FixEntity and Suggestion models through a new relationship entity (FixEntitySuggestion). This enables cascading operations and bulk updates, allowing a single FixEntity to be associated with multiple Suggestions and vice versa.
Related PRs -
adobe/spacecat-api-service#1316
https://github.com/adobe/spacecat-autofix-worker/pull/251

📋 Changes

New Model: FixEntitySuggestion (Relationship Entity)

Purpose & Design:
The FixEntitySuggestion model serves as a relationship entity that connects FixEntity and Suggestion entities in a many-to-many association. This design pattern enables:

  • A single FixEntity to address multiple Suggestions
  • Multiple FixEntities to reference the same Suggestion
  • Efficient querying in both directions
  • Independent lifecycle management of the relationship

Data Model:

{
  suggestionId: string;           // Primary partition key - links to Suggestion
  fixEntityId: string;            // Primary sort key - links to FixEntity
  opportunityId: string;          // Denormalized for efficient querying
  fixEntityCreatedAt: string;     // ISO timestamp from parent FixEntity
  fixEntityCreatedDate: string;   // Auto-derived date (YYYY-MM-DD) for indexing
  createdAt: string;              // Relationship creation timestamp
  updatedAt: string;              // Relationship last update timestamp
}

Indexing Strategy:

  • Primary Index: Enables efficient lookups of all FixEntities for a given Suggestion
    • PK: suggestionId
    • SK: fixEntityId
  • Secondary Index (GSI): Supports time-based queries at the opportunity level
    • PK: opportunityId
    • SK: Composite of fixEntityCreatedDate + updatedAt
    • Use case: Query all fix-suggestion relationships for an opportunity, sorted by date

Key Operations:

  • allBySuggestionId(suggestionId): Retrieves all relationship records for a given Suggestion, effectively returning which FixEntities are associated
  • allByFixEntityId(fixEntityId): Retrieves all relationship records for a given FixEntity, effectively returning which Suggestions it addresses
  • allByOpportunityIdAndFixEntityCreatedDate(opportunityId, fixEntityCreatedDate): Queries relationship records by opportunity and date, enabling efficient date-based filtering (auto-generated from GSI)
  • Automatic cascade management: When creating/updating relationships, orphaned records are automatically removed to maintain data integrity

Benefits:

  1. Flexibility: Supports complex autofix scenarios where one fix addresses multiple issues or multiple fixes target the same issue
  2. Traceability: Maintains full audit trail of which fixes address which suggestions
  3. Performance: Optimized queries prevent N+1 problems when fetching related entities
  4. Data Integrity: Ensures both sides of the relationship exist before creating the association

Enhanced FixEntity Model

  • getSuggestionsByFixEntityId(fixEntityId):

    • Retrieves all suggestions associated with a specific FixEntity
    • Fetches relationship records via FixEntitySuggestionCollection.allByFixEntityId()
    • Performs batch lookup of actual Suggestion entities
    • Returns full Suggestion objects with all properties
  • setSuggestionsForFixEntity(fixEntityId, suggestionIds):

    • Manages the complete set of suggestions for a FixEntity
    • Validation phase: Verifies all suggestion IDs exist in the database
    • Diff calculation: Compares new set against existing relationships
    • Upsert new: Creates relationship records for new associations
    • Cleanup old: Removes relationship records no longer in the set
    • Idempotent: Safe to call repeatedly with the same data
    • Returns both successfully created relationships and any validation errors

Enhanced Suggestion Model

  • getFixEntitiesBySuggestionId(suggestionId):
    • Retrieves all FixEntities that address a specific Suggestion
    • Fetches relationship records via FixEntitySuggestionCollection.allBySuggestionId()
    • Performs batch lookup of actual FixEntity objects
    • Enables tracking which fixes have been deployed for a suggestion

Opportunity Model - Cascading Logic

  • Enhanced addFixEntities(fixEntities) with atomic relationship management:

    Input Format: Each fixEntity must include a suggestions array:

    {
      type: 'CODE_CHANGE',
      status: 'PENDING',
      suggestions: ['suggestion-id-1', 'suggestion-id-2'], // Required array
      // ... other fixEntity properties
    }

    Return Value:

    {
      createdItems: [/* successfully created FixEntity instances */],
      errorItems: [
        { item: {/* original fixEntity */}, error: Error },
        // ... more errors
      ]
    }

Base Collection Enhancements

  • batchGetByKeys(keys):

    • Generic method for efficient batch retrieval
    • Accepts array of key objects (e.g., [{ suggestionId: 'id1' }, ...])
    • Uses DynamoDB BatchGetItem for optimal performance
    • Returns both successfully fetched items and unprocessed keys
  • removeByIndexKeys(keys):

    • Bulk deletion method for removing multiple items by their index keys
    • Accepts array of key objects matching any index (primary or GSI)
    • Validates all keys are non-empty objects
    • Efficiently removes items in batch operation
    • Critical for cascade deletion and cleanup operations
    • Used internally by setSuggestionsForFixEntity to remove orphaned relationships

Utilities

  • createQueryPattern(sortKeys):
    • Generates DynamoDB query pattern strings from sort key definitions
    • Handles composite sort keys with proper delimiter
    • Used internally for GSI queries

🎫 Related Issue

SITES-34129

Please ensure your pull request adheres to the following guidelines:

  • make sure to link the related issues in this description
  • when merging / squashing, make sure the fixed issue references are visible in the commits, for easy compilation of release notes

Related Issues

Thanks for contributing!

@sandsinh sandsinh marked this pull request as draft October 1, 2025 06:21
Copy link

github-actions bot commented Oct 2, 2025

This PR will trigger a patch release when merged.

* @throws {DataAccessError} - Throws an error if the IDs are not provided or if the batch
* operation fails.
*/
async batchGetByKeys(keys) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be paginated? should we use projection to lessen the load while indicating only needed properties (derfault could be all)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BatchGet in Electrodb does not support pagination. ❌
Projection is supported. I have added it into options now. ✅

@sandsinh sandsinh merged commit 8739d2b into main Oct 16, 2025
7 checks passed
@sandsinh sandsinh deleted the SITES-34129 branch October 16, 2025 14:17
solaris007 pushed a commit that referenced this pull request Oct 16, 2025
# [@adobe/spacecat-shared-data-access-v2.72.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.71.1...@adobe/spacecat-shared-data-access-v2.72.0) (2025-10-16)

### Features

* Sites 34129 adds many to many relationship between Fix Entity and Suggestions ([#993](#993)) ([8739d2b](8739d2b))
@solaris007
Copy link
Member

🎉 This PR is included in version @adobe/spacecat-shared-data-access-v2.72.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

danieljchuser pushed a commit that referenced this pull request Oct 17, 2025
…nd Suggestions (#993)

### 🎯 Purpose
Implements a many-to-many relationship between `FixEntity` and
`Suggestion` models through a new relationship entity
(`FixEntitySuggestion`). This enables cascading operations and bulk
updates, allowing a single `FixEntity` to be associated with multiple
`Suggestions` and vice versa.
Related PRs - 
adobe/spacecat-api-service#1316
adobe/spacecat-autofix-worker#251

### 📋 Changes

#### New Model: FixEntitySuggestion (Relationship Entity)

**Purpose & Design:**
The `FixEntitySuggestion` model serves as a relationship entity that
connects `FixEntity` and `Suggestion` entities in a many-to-many
association. This design pattern enables:
- A single `FixEntity` to address multiple `Suggestions`
- Multiple `FixEntities` to reference the same `Suggestion`
- Efficient querying in both directions
- Independent lifecycle management of the relationship

**Data Model:**
```typescript
{
  suggestionId: string;           // Primary partition key - links to Suggestion
  fixEntityId: string;            // Primary sort key - links to FixEntity
  opportunityId: string;          // Denormalized for efficient querying
  fixEntityCreatedAt: string;     // ISO timestamp from parent FixEntity
  fixEntityCreatedDate: string;   // Auto-derived date (YYYY-MM-DD) for indexing
  createdAt: string;              // Relationship creation timestamp
  updatedAt: string;              // Relationship last update timestamp
}
```

**Indexing Strategy:**
- **Primary Index**: Enables efficient lookups of all FixEntities for a
given Suggestion
  - PK: `suggestionId`
  - SK: `fixEntityId`
- **Secondary Index (GSI)**: Supports time-based queries at the
opportunity level
  - PK: `opportunityId`
  - SK: Composite of `fixEntityCreatedDate` + `updatedAt`
- Use case: Query all fix-suggestion relationships for an opportunity,
sorted by date

**Key Operations:**
- **`allBySuggestionId(suggestionId)`**: Retrieves all relationship
records for a given Suggestion, effectively returning which FixEntities
are associated
- **`allByFixEntityId(fixEntityId)`**: Retrieves all relationship
records for a given FixEntity, effectively returning which Suggestions
it addresses
- **`allByOpportunityIdAndFixEntityCreatedDate(opportunityId,
fixEntityCreatedDate)`**: Queries relationship records by opportunity
and date, enabling efficient date-based filtering (auto-generated from
GSI)
- **Automatic cascade management**: When creating/updating
relationships, orphaned records are automatically removed to maintain
data integrity

**Benefits:**
1. **Flexibility**: Supports complex autofix scenarios where one fix
addresses multiple issues or multiple fixes target the same issue
2. **Traceability**: Maintains full audit trail of which fixes address
which suggestions
3. **Performance**: Optimized queries prevent N+1 problems when fetching
related entities
4. **Data Integrity**: Ensures both sides of the relationship exist
before creating the association

#### Enhanced FixEntity Model
- **`getSuggestionsByFixEntityId(fixEntityId)`**: 
  - Retrieves all suggestions associated with a specific FixEntity
- Fetches relationship records via
`FixEntitySuggestionCollection.allByFixEntityId()`
  - Performs batch lookup of actual Suggestion entities
  - Returns full Suggestion objects with all properties
  
- **`setSuggestionsForFixEntity(fixEntityId, suggestionIds)`**: 
  - Manages the complete set of suggestions for a FixEntity
- **Validation phase**: Verifies all suggestion IDs exist in the
database
- **Diff calculation**: Compares new set against existing relationships
  - **Upsert new**: Creates relationship records for new associations
  - **Cleanup old**: Removes relationship records no longer in the set
  - **Idempotent**: Safe to call repeatedly with the same data
- Returns both successfully created relationships and any validation
errors

#### Enhanced Suggestion Model
- **`getFixEntitiesBySuggestionId(suggestionId)`**: 
  - Retrieves all FixEntities that address a specific Suggestion
- Fetches relationship records via
`FixEntitySuggestionCollection.allBySuggestionId()`
  - Performs batch lookup of actual FixEntity objects
  - Enables tracking which fixes have been deployed for a suggestion

#### Opportunity Model - Cascading Logic
- **Enhanced `addFixEntities(fixEntities)`** with atomic relationship
management:
  
  **Input Format**: Each fixEntity must include a `suggestions` array:
  ```javascript
  {
    type: 'CODE_CHANGE',
    status: 'PENDING',
suggestions: ['suggestion-id-1', 'suggestion-id-2'], // Required array
    // ... other fixEntity properties
  }
  ```
  
  **Return Value**:
  ```javascript
  {
    createdItems: [/* successfully created FixEntity instances */],
    errorItems: [
      { item: {/* original fixEntity */}, error: Error },
      // ... more errors
    ]
  }
  ```

#### Base Collection Enhancements
- **`batchGetByKeys(keys)`**: 
  - Generic method for efficient batch retrieval
- Accepts array of key objects (e.g., `[{ suggestionId: 'id1' }, ...]`)
  - Uses DynamoDB BatchGetItem for optimal performance
  - Returns both successfully fetched items and unprocessed keys

- **`removeByIndexKeys(keys)`**: 
  - Bulk deletion method for removing multiple items by their index keys
  - Accepts array of key objects matching any index (primary or GSI)
  - Validates all keys are non-empty objects
  - Efficiently removes items in batch operation
  - Critical for cascade deletion and cleanup operations
- Used internally by `setSuggestionsForFixEntity` to remove orphaned
relationships
  
#### Utilities
- **`createQueryPattern(sortKeys)`**: 
  - Generates DynamoDB query pattern strings from sort key definitions
  - Handles composite sort keys with proper delimiter
  - Used internally for GSI queries

### 🎫 Related Issue
SITES-34129

Please ensure your pull request adheres to the following guidelines:
- [ ] make sure to link the related issues in this description
- [ ] when merging / squashing, make sure the fixed issue references are
visible in the commits, for easy compilation of release notes

## Related Issues


Thanks for contributing!
danieljchuser pushed a commit that referenced this pull request Oct 17, 2025
# [@adobe/spacecat-shared-data-access-v2.72.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v2.71.1...@adobe/spacecat-shared-data-access-v2.72.0) (2025-10-16)

### Features

* Sites 34129 adds many to many relationship between Fix Entity and Suggestions ([#993](#993)) ([8739d2b](8739d2b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants