A small in-memory, file-persisted database engine with an interactive CLI, built in Java. Supports multiple databases, tables with typed fields and primary/secondary keys, row-level CRUD, batch command execution from a file, and automatic on-disk persistence that survives restarts.
- JDK 11+
- JLine3 (
jline-3.21.0.jar, included in this repo)
javac -cp "jline-3.21.0.jar" *.javajava -cp ".;jline-3.21.0.jar" Cli(On Linux/macOS, use : instead of ; as the classpath separator.)
On first launch (no persisted data yet), the CLI automatically runs a bundled demo dataset (tests/test_data.txt) so there's something to explore immediately. On later launches, it reloads whatever you'd previously created from data/.
Commands follow <resource> <action> [args...], where resource is db, table, or row:
db create <name>
db select <name>
db delete <name>
db list
db help
table create <name> <field:TYPE[:KEYTYPE]> [...]
table select <name>
table delete <name>
table list
table help
row create <field> <value> [<field> <value> ...]
row get <keyField> <keyValue>
row update <keyField> <keyValue> <field> <value>
row delete <keyField> <keyValue>
row list
row help
Field types: LONG, STRING. Key types (optional, third segment of a field spec): PRIMARY, SECONDARY, or omitted for a plain field.
- PRIMARY — must be unique across rows; can be looked up/updated/deleted by
- SECONDARY — duplicates allowed; can still be looked up/updated/deleted by
- A plain field cannot be used to look up a row
run [file] Execute every line of a command file (defaults to tests/test_data.txt)
help Show help
quit / exit Exit the CLI
db create shop
db select shop
table create products id:LONG:PRIMARY sku:STRING:SECONDARY name:STRING price:LONG
table select products
row create id 1 sku ABC100 name Laptop price 1200
row create id 2 sku ABC100 name Mouse price 25
row get id 1
row get sku ABC100
row update id 1 price 1150
row delete id 2
row list
Every successful create/update/delete command is written immediately to data/<database>.dblog — a plain-text file of the exact commands needed to reconstruct that database. There's no separate "save" step; by the time a command finishes, it's already durable. Quitting and relaunching (or a crash) loses nothing beyond whatever command was still mid-flight.
run path/to/commands.txt
Reads the file line by line, executes each one, and prints a Warning: with the exact line number for any command that fails — while still running the rest of the file. Useful for bulk data loading or scripted testing.
A generated regression suite exercises the full command set (help text, error handling, primary/secondary key semantics, bulk load performance, persistence) end-to-end through the actual CLI binary:
./tests/run_tests.sh [bulk_row_count] # default 10000This regenerates tests/test_data.txt, runs it through the CLI, and asserts on the output transcript.
Cli.java REPL loop, command dispatch, run/bootstrap logic
CliCmd.java Abstract base for db/table/row command handlers
DatabaseCliCmd.java "db" resource: create/select/delete/list
TableCliCmd.java "table" resource: create/select/delete/list
RowCliCmd.java "row" resource: create/get/update/delete/list
Database.java In-memory table registry
Table.java Field schema, primary/secondary keys, row storage
Row.java A single row's field values
DatabasePersistenceLog.java Appends successful mutations to a database's log file
tests/ Test data generator and regression suite