Hi there! I'm Shrijith Venkatrama, the founder of Hexmos. Right now, I’m building LiveAPI, a super-convenient tool that simplifies engineering workflows by generating awesome API docs from your code in minutes.
In this tutorial series, I am on a journey to build for myself DBChat - a simple tool for using AI chat to explore and evolve databases.
See previous posts to get more context:
Kicking Off The DBChat Project
The first step is to start a GoLang project:
go mod init dbchat
mkdir -p cmd/dbchat pkg
touch cmd/dbchat/main.go
Then let's create a skeleton cmd/dbchat/main.go
like this:
package main
import (
"fmt"
"log"
)
func main() {
log.Println("Starting dbchat application...")
fmt.Println("Welcome to dbchat!")
}
Also, let's create a convenience Makefile
at the project root to build, run and clean go artifacts out of our source:
# Binary name
BINARY_NAME=dbchat
# Build directory
BUILD_DIR=build
# Go build flags
BUILD_FLAGS=-v
.PHONY: build run clean
# Build the application
build:
@echo "Building ${BINARY_NAME}..."
@mkdir -p ${BUILD_DIR}
@go build ${BUILD_FLAGS} -o ${BUILD_DIR}/${BINARY_NAME} ./cmd/dbchat
# Run the application
run:
@go run ./cmd/dbchat
# Clean build artifacts
clean:
@echo "Cleaning..."
@rm -rf ${BUILD_DIR}
Running dbchat
for Testing Purposes
make run
Building dbchat
to Get a Binary Output
make build
cd build
./dbchat
And we get this nice output:
2025/01/10 22:51:37 Starting dbchat...
Welcome to dbchat!
Implementing a Basic REPL Loop
The next thing we want to do is - get a basic REPL going. In simpler words - you can call it an "interactive shell".
Usually, in C, et-cetera, the readline library within a loop is how it's achieved.
In Golang, I was shopping around for any helper libraries that can save our time from implementing our own
REPL from scratch.
go-repl
Something that looks sort of good for our purposes is go-repl
As you can see - it gives us many "goodies" which we are used to in a typical shell environment. Let's plug it in for now,
if necessary we will change later.
Getting Started with go-repl
Turns out the original repo is at: https://github.com/OpenEngineer/go-repl
And we find an example in the the README in that repo.
So I make a adaption, and turn my main.go
to look something like this:
package main
import (
"fmt"
"log"
"strings"
repl "github.com/openengineer/go-repl"
)
const banner = `
██████╗ ██████╗ ██████╗██╗ ██╗ █████╗ ████████╗
██╔══██╗██╔══██╗██╔════╝██║ ██║██╔══██╗╚══██╔══╝
██║ ██║██████╔╝██║ ███████║███████║ ██║
██║ ██║██╔══██╗██║ ██╔══██║██╔══██║ ██║
██████╔╝██████╔╝╚██████╗██║ ██║██║ ██║ ██║
╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
`
var helpMessage = `Available commands:
help display this message
hello get a friendly greeting
quit quit DBChat`
// implements repl.Handler interface
type DBChatHandler struct {
r *repl.Repl
}
func main() {
log.Println("Starting dbchat...")
fmt.Println(banner)
fmt.Println("Welcome to DBChat! Type 'help' for available commands.")
h := &DBChatHandler{}
h.r = repl.NewRepl(h)
// start the terminal loop
if err := h.r.Loop(); err != nil {
log.Fatal(err)
}
}
func (h *DBChatHandler) Prompt() string {
return "dbchat> "
}
func (h *DBChatHandler) Tab(buffer string) string {
return "" // do nothing for now
}
func (h *DBChatHandler) Eval(line string) string {
fields := strings.Fields(line)
if len(fields) == 0 {
return ""
}
cmd, _ := fields[0], fields[1:]
switch cmd {
case "help":
return helpMessage
case "hello":
return "Hello! Welcome to DBChat! 👋"
case "quit":
h.r.Quit()
return "Goodbye! 👋"
default:
return fmt.Sprintf("Unknown command: %s\nType 'help' for available commands.", cmd)
}
}
Toy REPL Demo
I'm Impressed With How Productive One Can Be With GoLang
So this whole thing took around 45 minutes - from nothing to a GoLang based toy REPL - with nice Makefile based automations. I chose GoLang for this exact reason - simple syntax, restrained feature-set, good standard libraries, and extensive open source libraries as well.
For example, the REPL library I am using doesn't seem like a major project - but it is so helpful to just get started with something rather than build everything ourselves to get something going.
Next Up
In the next post, I will try to tweak the REPL more towards the DBChat concept. Maybe I will focus on connecting to the database (postgresql first), and try to get an export of the entire schema.
Top comments (0)