Hone logo
Hone
Problems

Minimalist ORM Implementation in Python

This challenge asks you to implement a simplified Object-Relational Mapper (ORM) in Python. ORMs provide a layer of abstraction between your application code and the database, allowing you to interact with data using objects instead of raw SQL queries. Building a basic ORM will help you understand the core concepts behind database interaction and object mapping.

Problem Description

You are tasked with creating a rudimentary ORM that supports basic CRUD (Create, Read, Update, Delete) operations for a single table in a SQLite database. The ORM should allow you to define a model class representing the table, map attributes of the model to columns in the table, and perform operations on the table using instances of the model.

Key Requirements:

  • Model Definition: You should be able to define a model class that inherits from a base class provided by your ORM. This model class should specify the table name and the mapping between class attributes and database columns.
  • CRUD Operations: The ORM should provide methods for:
    • create(model_instance): Inserts a new row into the database based on the model instance's attributes.
    • get(model_class, id): Retrieves a model instance from the database based on its primary key (id).
    • update(model_instance): Updates an existing row in the database with the model instance's attributes.
    • delete(model_instance): Deletes a row from the database based on the model instance's primary key (id).
  • Database Connection: The ORM should handle the connection to a SQLite database. The database file path should be configurable.
  • Primary Key: The ORM should assume that each table has a primary key column named 'id' which is an integer.

Expected Behavior:

  • The ORM should correctly map model attributes to database columns.
  • CRUD operations should execute the appropriate SQL queries and interact with the database.
  • The get method should return None if no record with the given ID is found.
  • The ORM should handle potential database errors gracefully (e.g., connection errors, invalid SQL). For simplicity, you can raise exceptions in case of errors.

Edge Cases to Consider:

  • What happens if the database file doesn't exist?
  • What happens if the table doesn't exist? (For simplicity, assume the table is created when the first record is inserted).
  • What happens if you try to update a record that doesn't exist? (For simplicity, you can ignore this case).
  • What happens if you try to delete a record that doesn't exist? (For simplicity, you can ignore this case).

Examples

Example 1:

Input:
Model Definition:
class User(BaseModel):
    table = 'users'
    columns = ['id', 'name', 'email']

ORM Usage:
user = User(name='Alice', email='alice@example.com')
orm.create(user)

Output:
A new row is inserted into the 'users' table with the values: id=1, name='Alice', email='alice@example.com' (assuming id is auto-incrementing)

Explanation:
The `create` method generates an INSERT SQL query and executes it, inserting the user's data into the 'users' table.

Example 2:

Input:
Model Definition:
class Product(BaseModel):
    table = 'products'
    columns = ['id', 'name', 'price']

ORM Usage:
product = orm.get(Product, 1)

Output:
product = Product(id=1, name='Laptop', price=1200.00) (assuming a product with id=1 exists in the database)
or
product = None (if no product with id=1 exists)

Explanation:
The `get` method generates a SELECT SQL query to retrieve the product with id=1. If found, it creates a Product object and returns it. Otherwise, it returns None.

Example 3:

Input:
Model Definition:
class Book(BaseModel):
    table = 'books'
    columns = ['id', 'title', 'author']

ORM Usage:
book = Book(id=2, title='The Hitchhiker\'s Guide to the Galaxy', author='Douglas Adams')
orm.update(book)

Output:
The row with id=2 in the 'books' table is updated with the values: title='The Hitchhiker\'s Guide to the Galaxy', author='Douglas Adams'

Explanation:
The `update` method generates an UPDATE SQL query to update the book with id=2.

Constraints

  • Database: Use SQLite.
  • SQL Injection: For simplicity, you do not need to implement full SQL injection prevention. However, be mindful of potential vulnerabilities and avoid directly embedding user-provided data into SQL queries without proper sanitization (e.g., using parameterized queries).
  • Error Handling: Basic error handling is sufficient. Raising exceptions for database connection errors or invalid SQL is acceptable.
  • Performance: Performance is not a primary concern for this challenge. Focus on correctness and clarity.
  • Model Columns: Assume all columns are of string type unless the 'id' column which is an integer.

Notes

  • Start by defining a base BaseModel class that provides common functionality for all models.
  • Implement a simple ORM class that handles database connections and CRUD operations.
  • Consider using the sqlite3 module for database interaction.
  • Focus on the core functionality of the ORM. Advanced features like relationships, indexing, and complex queries are beyond the scope of this challenge.
  • The columns attribute in the model should define the order of columns in the table.
  • The id column is assumed to be auto-incrementing. You don't need to explicitly handle auto-incrementing in your code.
  • The create method should return the created object.
  • The get method should return None if the object is not found.
Loading editor...
python