Published on

Design an in-memory database (OOD)

Authors

Design an in-memory database (OOD)

Problem: Design an in-memory database using object-oriented principles.

How would you think to solve this problem using object-oriented principles in an interview?

Let's start by figuring out the classes that we can have in the system. We can have classes like Database , Table , Row and DatabaseManager.

What are the properties we can think of in a Row class? It can have properties like rowId (to uniquely identify a row), columnValuesMap (key-value pairs), createdAt and updateAt. Below is an implementation of Row class in java.

import java.util.Date;
import java.util.HashMap;

public class Row {
    private String rowId;
    private HashMap<String, String> columnValuesMap;
    private Date createdAt;
    private Date UpdatedAt;

    public Row(String rowId, HashMap<String, String> columnsMap, Date createdAt, Date updatedAt) {
        this.rowId = rowId;
        this.columnValuesMap = columnsMap;
        this.createdAt = createdAt;
        UpdatedAt = updatedAt;
    }

    public HashMap<String, String> getColumnValuesMap() {
        return columnValuesMap;
    }

    public void setColumnValuesMap(HashMap<String, String> columnValuesMap) {
        this.columnValuesMap = columnValuesMap;
    }

    public String getRowId() {
        return rowId;
    }

    public void setRowId(String rowId) {
        this.rowId = rowId;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }

    public Date getUpdatedAt() {
        return UpdatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        UpdatedAt = updatedAt;
    }
}

A table will consist of several rows. It should support all the CRUD operations. It should support functionality like adding a row, updating a row, deleting a row, and reading a row. Below is an implementation of a Table class in java.

import java.util.Date;
import java.util.HashMap;

public class Table {
    private String tableName;
    private HashMap<String, Row> rows;
    private Date createdAt;

    public Table(String tableName) {
        this.tableName = tableName;
        this.rows = new HashMap<>();
        this.createdAt = new Date();
    }

    public void insertEntry(String rowId, HashMap<String, String> columnsMap) {
        if (rows.containsKey(rowId)) {
            System.out.println("Duplicate primary key : " + " Insertion failed");
        } else {
            Row row =  new Row(rowId, columnsMap, new Date(), new Date());
            rows.put(rowId, row);
            System.out.println("Successfully added a row");
        }
    }

    public void updateEntry(String rowId, HashMap<String, String>valuesMap) {
        Row row = rows.get(rowId);
        valuesMap.forEach( (k, v) -> {
            row.getColumnValuesMap().put(k, v);
        });
        System.out.println("Row successfully updated");
        row.setUpdatedAt(new Date());
    }

    public void deleteEntry(String rowId) {
        System.out.println("Row successfully deleted");
        rows.remove(rowId);
    }

    public HashMap<String, String> readEntry(String rowId) {
        return rows.get(rowId).getColumnValuesMap();
    }


    public HashMap<String, Row> getRows() {
        return rows;
    }

    public void setRows(HashMap<String, Row> rows) {
        this.rows = rows;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
}

Every table is a part of a database. This indicates that a Database will have a map of tables. Also, it should support operations like creating a table and deleting a table. This is how a Database class’s implementation looks like.

import java.util.Date;
import java.util.HashMap;

public class Database {
    private String name;
    private HashMap<String, Table> tableHashMap;
    private Date createdAt;

    public Database(String name) {
        this.name = name;
        this.tableHashMap = new HashMap<>();
        this.createdAt = new Date();
    }

    public Table createTable(String tableName) {
        if (tableHashMap.containsKey(tableName)) {
            System.out.println("A table already exists with the given name");
        } else {
            Table table = new Table(tableName);
            tableHashMap.put(tableName, table);
            System.out.println("Table successfully created");
        }
        return tableHashMap.get(tableName);
    }

    public void dropTable(String tableName) {
        tableHashMap.remove(tableName);
        System.out.println("Table successfully dropped");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HashMap<String, Table> getTableHashMap() {
        return tableHashMap;
    }

    public void setTableHashMap(HashMap<String, Table> tableHashMap) {
        this.tableHashMap = tableHashMap;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
}

As we know that in a database management system we can create a database and delete a database. For this purpose, we need a DatabaseManager class to manage the database.

import java.util.HashMap;

public class DatabaseManager {
    private HashMap<String, Database> databaseHashMap;

    public DatabaseManager() {
        this.databaseHashMap = new HashMap<>();
    }

    public Database createDatabase(String databaseName) {
        if (databaseHashMap.containsKey(databaseName)) {
            System.out.println("A database already exists with this name");
        } else {
            databaseHashMap.put(databaseName, new Database(databaseName));
        }
        return databaseHashMap.get(databaseName);
    }

    public void deleteDatabase(String databaseName) {
        databaseHashMap.remove(databaseName);
    }

    public HashMap<String, Database> getDatabaseHashMap() {
        return databaseHashMap;
    }

    public void setDatabaseHashMap(HashMap<String, Database> databaseHashMap) {
        this.databaseHashMap = databaseHashMap;
    }
}

A basic Main class to test the code.

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        DatabaseManager databaseManager = new DatabaseManager();

        Database db1 = databaseManager.createDatabase("db1");

        Table table1 = db1.createTable("students");
        table1.insertEntry("1", new HashMap<String, String>() {{
            put("name", "Ashwani");
            put("age", "21");
        }});
        table1.insertEntry("2", new HashMap<String, String>() {{
            put("name", "John");
            put("age", "20");
        }});
        System.out.println(table1.readEntry("1"));

        Table table2 = db1.createTable("subjects");
        table2.insertEntry("1", new HashMap<String, String>() {{
            put("name", "CSE");
            put("teacher", "alan");
        }});
        table2.insertEntry("2", new HashMap<String, String>() {{
            put("name", "EEE");
            put("teacher", "paul");
        }});
        System.out.println(table2.readEntry("1"));

    }
}

This completes the design of an in-memory database using object-oriented principles.

Thanks for reading :)