Hone logo
Hone
Problems

Implementing Data Migrations in an Angular Application

Data migrations are essential for evolving your application's data structure over time, especially as your application grows and requirements change. This challenge asks you to implement a simple data migration system within an Angular application to handle a scenario where a user profile's address format needs to be updated. Successfully completing this challenge demonstrates understanding of Angular services, dependency injection, and a structured approach to managing data transformations.

Problem Description

You are tasked with creating a data migration system within an Angular application. The application currently stores user profile data, including an address, in a simple format. Due to evolving requirements, the address format needs to be changed from a single address string to separate street, city, and zipCode properties.

Your goal is to implement a migration service that can be triggered to update existing user profile data to the new address format. The migration service should:

  1. Identify Users Needing Migration: Assume you have a service that fetches user profiles from a mock data source (provided below). This service should be used to identify users whose address is in the old format (a single string).
  2. Transform Address Data: For each user identified, the migration service should parse the existing address string and split it into street, city, and zipCode properties. Assume the address string is always in the format: "123 Main St, Anytown, 12345".
  3. Update User Profiles: The migration service should update the user profile data with the new address format. Assume you have a function updateUserProfile(userId: string, updatedProfile: UserProfile) : Promise<void> that handles the actual update to the data store (mocked in this case).
  4. Handle Errors: The migration service should gracefully handle potential errors during the parsing or updating process.

Expected Behavior:

  • The migration service should iterate through all user profiles.
  • For users with an address in the old format, the address should be parsed and updated.
  • For users with an address already in the new format, no changes should be made.
  • The migration process should be asynchronous.
  • Error handling should prevent the entire migration from failing due to a single error.

Edge Cases to Consider:

  • What if the address string is not in the expected format? (Handle gracefully, log the error, and continue with the next user).
  • What if the updateUserProfile function fails for a particular user? (Handle gracefully, log the error, and continue with the next user).
  • What if there are no users needing migration? (The service should complete without errors).

Examples

Example 1:

Input:
Mock User Data:
[
  { id: '1', name: 'Alice', address: '456 Oak Ave, Springfield, 67890' },
  { id: '2', name: 'Bob', address: '789 Pine Ln, Hill Valley, 54321' },
  { id: '3', name: 'Charlie', address: { street: '101 Elm Rd', city: 'Riverdale', zipCode: '98765' } }
]

Output:
Updated User Data (after migration):
[
  { id: '1', name: 'Alice', address: { street: '456 Oak Ave', city: 'Springfield', zipCode: '67890' } },
  { id: '2', name: 'Bob', address: { street: '789 Pine Ln', city: 'Hill Valley', zipCode: '54321' } },
  { id: '3', name: 'Charlie', address: { street: '101 Elm Rd', city: 'Riverdale', zipCode: '98765' } }
]
Explanation: Users 1 and 2 had addresses in the old format and were updated. User 3 already had the new format and was not modified.

Example 2:

Input:
Mock User Data:
[
  { id: '1', name: 'Alice', address: 'Invalid Address Format' },
  { id: '2', name: 'Bob', address: '789 Pine Ln, Hill Valley, 54321' }
]

Output:
Updated User Data (after migration):
[
  { id: '1', name: 'Alice', address: 'Invalid Address Format' },
  { id: '2', name: 'Bob', address: { street: '789 Pine Ln', city: 'Hill Valley', zipCode: '54321' } }
]
Explanation: User 1's address could not be parsed, so it was left unchanged. User 2 was updated successfully.

Constraints

  • Data Source: You will use a mock data source for user profiles. The getUserProfiles() function is provided below.
  • Address Format: The old address format is a single string: "Street, City, ZipCode".
  • Address Parsing: The parsing logic must be robust enough to handle invalid address formats gracefully.
  • Asynchronous Operations: The migration process must be asynchronous.
  • Error Handling: Errors during parsing or updating should be logged and handled without stopping the entire migration.
  • Performance: The migration should be reasonably efficient for a small dataset (up to 100 users). Optimization is not the primary focus.

Notes

  • You will need to create an Angular service to encapsulate the migration logic.
  • Use dependency injection to provide the mock data source and the updateUserProfile function to the migration service.
  • Consider using async/await or Promises for asynchronous operations.
  • Logging errors is crucial for debugging and monitoring the migration process.
  • The updateUserProfile function is a placeholder; you don't need to implement actual data persistence. Focus on the migration logic itself.

Mock Data and Functions:

interface UserProfile {
  id: string;
  name: string;
  address: string | { street: string; city: string; zipCode: string };
}

async function getUserProfiles(): Promise<UserProfile[]> {
  return [
    { id: '1', name: 'Alice', address: '456 Oak Ave, Springfield, 67890' },
    { id: '2', name: 'Bob', address: '789 Pine Ln, Hill Valley, 54321' },
    { id: '3', name: 'Charlie', address: { street: '101 Elm Rd', city: 'Riverdale', zipCode: '98765' } },
    { id: '4', name: 'David', address: 'Invalid Address Format' }
  ];
}

async function updateUserProfile(userId: string, updatedProfile: UserProfile): Promise<void> {
  // Simulate an update operation.  No actual data persistence needed.
  console.log(`Updating user ${userId} with profile:`, updatedProfile);
  return Promise.resolve();
}
Loading editor...
typescript