Hone logo
Hone
Problems

Implementing CQRS for a Simple Blog Post System

The Command Query Responsibility Segregation (CQRS) pattern separates read and write operations for data. This challenge asks you to implement a simplified version of CQRS for a blog post system, demonstrating the separation of concerns and potential benefits of this architectural pattern. You'll be building separate handlers for commands (creating, updating, deleting posts) and queries (retrieving posts).

Problem Description

You are tasked with designing and implementing a basic blog post system using the CQRS pattern in Python. The system should allow users to create, update, and delete blog posts, as well as retrieve them. The core of the challenge lies in separating the command side (handling write operations) from the query side (handling read operations).

What needs to be achieved:

  1. Command Handlers: Implement handlers for the following commands:
    • CreatePost(title, content): Creates a new blog post.
    • UpdatePost(postId, title, content): Updates an existing blog post.
    • DeletePost(postId): Deletes a blog post.
  2. Query Handlers: Implement handlers for the following queries:
    • GetPost(postId): Retrieves a specific blog post by its ID.
    • GetAllPosts(): Retrieves all blog posts.
  3. Data Storage: Use an in-memory dictionary to store the blog posts. This simplifies the challenge and focuses on the CQRS implementation. The dictionary key will be the postId.
  4. Post Representation: A blog post should be represented as a dictionary with the following keys: id, title, and content. The id should be a unique integer generated automatically upon creation.

Key Requirements:

  • Separation of Concerns: Clearly separate command and query handlers.
  • Id Generation: Automatically generate unique IDs for new blog posts.
  • Error Handling: Handle cases where a post is not found during update or delete operations. Return appropriate error messages (strings) in these cases.
  • Data Consistency: Ensure that the in-memory store is updated correctly after each command.

Expected Behavior:

  • Creating a new post should add a new entry to the in-memory store with a unique ID.
  • Updating a post should modify the existing entry in the store.
  • Deleting a post should remove the entry from the store.
  • Retrieving a post should return the post data if it exists, or an error message if it doesn't.
  • Retrieving all posts should return a list of all posts in the store.

Edge Cases to Consider:

  • Attempting to update or delete a non-existent post.
  • Duplicate post titles (not strictly required, but good to consider).
  • Empty title or content during post creation.

Examples

Example 1:

Input:
Commands:
  CreatePost("My First Post", "This is the content of my first post.")
  CreatePost("Another Post", "Some more content here.")
Queries:
  GetAllPosts()
Output:
[
  {'id': 1, 'title': 'My First Post', 'content': 'This is the content of my first post.'},
  {'id': 2, 'title': 'Another Post', 'content': 'Some more content here.'}
]
Explanation: Two posts are created and retrieved.  The IDs are automatically assigned.

Example 2:

Input:
Commands:
  CreatePost("My First Post", "This is the content of my first post.")
Queries:
  GetPost(1)
Output:
{'id': 1, 'title': 'My First Post', 'content': 'This is the content of my first post.'}
Explanation: A post is created, then retrieved by its ID.

Example 3:

Input:
Commands:
  CreatePost("My First Post", "Initial content.")
  UpdatePost(1, "My Updated Post", "This is the updated content.")
Queries:
  GetPost(1)
Output:
{'id': 1, 'title': 'My Updated Post', 'content': 'This is the updated content.'}
Explanation: A post is created, then updated.  Retrieving the post shows the updated content.

Example 4:

Input:
Commands:
  CreatePost("My First Post", "Initial content.")
Queries:
  DeletePost(1)
  GetPost(1)
Output:
"Post not found"
Explanation: A post is created, then deleted. Attempting to retrieve it results in an error.

Constraints

  • In-Memory Storage: The data must be stored in an in-memory dictionary. No external databases are allowed.
  • Unique IDs: Post IDs must be unique integers.
  • Error Messages: Error messages should be strings.
  • Time Complexity: Query operations (GetPost, GetAllPosts) should have an average time complexity of O(1) and O(n) respectively, given the in-memory storage. Command operations (CreatePost, UpdatePost, DeletePost) should also aim for O(1) average time complexity.
  • Input Validation: Basic input validation (e.g., checking for empty titles/content) is recommended but not strictly required.

Notes

  • Focus on the CQRS pattern implementation rather than complex data validation or persistence.
  • Consider using classes or functions to encapsulate the command and query handlers.
  • Think about how to handle potential concurrency issues if this were a real-world application (although concurrency is not a requirement for this challenge).
  • The goal is to demonstrate the separation of read and write operations and the benefits of the CQRS pattern in a simplified context.
Loading editor...
python