In this video you will see a To Do List Application using Golang, MySQL database using CRUD principles and using a CLI with a menu to interect with the app.
CRUD Application.
Connected to MySQL database.
Command line interface (CLI).
User friendly.
Golang
MySQL
Git
Github
OBS Studio
Clipchamp Editor
'bufio' more info
'database/sql' more info
'fmt' more info
'os' more info
'time' more info
'go-sql-driver/mysql' more info
Perform unit tests to check edge cases.
Implement some GUI for better user experience.
Set a time limit to accomplish the task.
Create/implement an API that sends reminders to your email.
TO DO LIST CLI by Zetacoder. From scratch.
This document is created in order to organize the ideas before the creation of the proyect.
Im going to build a clasic TO DO LIST in CRUD model with a CLI from scratch.
FEATURES OF THE APP:
-Will be managed using CLI with the users inputs.
-Will be connected to an MySQL database.
-Will contain a MENU with options.
-You will be able to:
1) CREATE new tasks that will be storaged in MySQL database.
2) READ the task already storaged in the db and show it in screen.
3) UPDATE the tasks and modify it.
4) DELETE the task marked as completed.
5) DELETE the task you not longer want to do.
6) EXIT the program.
-The program will be interactive, returning messages in order to enhanced tu user experience.
PROJECT STRUCTURE:
to-do-list
-main.go ->
-mod.go -> modules to integrate the packages dependency
-sum.go
-crud -> contains the CREATE, READ, UPDATE and DELETE funcs.
-ideas.txt
-to-do-list.exec -> executes the programm.
PACKAGES:
_ "github.com/go-sql-driver/mysql" -> A MySQL-Driver for Go's database/sql package
"database/sql" -> Contains funcs to open, prepare, query, manipulate the database and more.
"fmt"
"time"
DATA STRUCTURES:
-Every TASK have the following structure:
1) ID of the task --> int
2) Name of the task --> string
3) Description of the task --> string
4) Responsable of the task --> string
5) State of completion --> bool
-MySQL Database:
Name of database: to_do_list
Name of table: tasks
-ID -> TINYINT primary key INCREMENTAL NOT NULL
-NAME_TASK -> TINYTEXT NOT NULL
-DESCRIPTION -> TINYTEXT NOT NULL
-RESPONSABLE -> TINYTEXT NOT NULL
-COMPLETED -> BOOL (0 for false, 1 for true.)
LOGICAL STEPS OF THE APP:
1) Create the to_do_list DATABASE on MYSQL.
2) Connect to DATABASE
3) Salute the user and show the MENU and INSTRUCTIONS.
*show instructions
(1) CREATE task to do
(2) READ the tasks
(3) UPDATE the task
(4) MARK the task as completed.
(5) DELETE task.
(6) Exit the programm.
4) Scan the answer and executes the func dependening on the option.
5) Return the result on screen of the func. Repeat main menu (step 3).
6) If option selected 6, exit programm.
package main
import (
"bufio"
"database/sql" // Contains funcs to open, prepare, query, manipulate the database and more.
"fmt"
"os"
"time"
_ "github.com/go-sql-driver/mysql" // A MySQL-Driver for Go's database/sql package
)
var selected_option int
var newTask Task
// checkErr checks if there is an error and panics if it is the case.
func checkErr(err error) {
if err != nil {
panic(err)
}
}
type Task struct {
ID int
Name_task string
Description string
Responsable string
Completed bool
}
// CREATE storage new inputs from the user and create new task.
func Create(t Task) (e error) {
db, err := sql.Open("mysql", "root:.@tcp(127.0.0.1:3306)/")
checkErr(err)
defer db.Close()
// Selected database.
_, err = db.Exec("USE to_do_list")
checkErr(err)
// We prepare for the input in order to prevent SQL injections.
prepareSentence, err := db.Prepare("INSERT INTO tasks (ID, name_task, description, responsable, completed) VALUES(?,?, ?,?,?)")
checkErr(err)
defer prepareSentence.Close()
// Execute sentence for every '?'
_, err = prepareSentence.Exec(t.ID, t.Name_task, t.Description, t.Responsable, t.Completed)
checkErr(err)
return nil
}
// READ selects rows from the MySQL table "to_do_list", reads it, scans it and returns a slice of the tasks.
func Read() ([]Task, error) {
var tasks []Task
// Open db.
db, err := sql.Open("mysql", "root:Pepperonipizza123.@tcp(127.0.0.1:3306)/")
checkErr(err)
defer db.Close()
// Selected database.
_, err = db.Exec("USE to_do_list")
checkErr(err)
// We execute a query iterating over all the rows.
rows, err := db.Query("SELECT * FROM tasks")
checkErr(err)
defer rows.Close()
var t Task
// We read all the rows asigning the values to t (type Task))
// Then, append the values to tasks and returning it.
for rows.Next() {
err = rows.Scan(&t.ID, &t.Name_task, &t.Description, &t.Responsable, &t.Completed)
checkErr(err)
tasks = append(tasks, t)
}
return tasks, nil
}
// UPDATE selects some task and modifies it.
func Update(n Task) error {
// Connected to MySQL database.
db, err := sql.Open("mysql", "root:Pepperonipizza123.@tcp(127.0.0.1:3306)/to_do_list")
checkErr(err)
// Close db after use.
defer db.Close()
preparedSentence, err := db.Prepare("UPDATE tasks SET name_task = ?, description = ?, responsable = ?, completed = ? WHERE id = ?")
checkErr(err)
defer preparedSentence.Close()
_, err = preparedSentence.Exec(n.Name_task, n.Description, n.Responsable, n.Completed, n.ID)
checkErr(err)
return nil
}
// DELETE selects some task and remove it from the db.
func Delete(n Task) error {
// Connected to MySQL database.
db, err := sql.Open("mysql", "root:Pepperonipizza123.@tcp(127.0.0.1:3306)/to_do_list")
checkErr(err)
// Close db after use.
defer db.Close()
preparedSentence, err := db.Prepare("DELETE FROM tasks WHERE ID = ?")
checkErr(err)
defer preparedSentence.Close()
_, err = preparedSentence.Exec(n.ID)
checkErr(err)
return nil
}
func main() {
// Connected to MySQL database.
db, err := sql.Open("mysql", "root:.@tcp(127.0.0.1:3306)/")
checkErr(err)
// Close db after use.
defer db.Close()
// Created To Do List Database.
_, err = db.Exec("CREATE DATABASE if not exists to_do_list")
checkErr(err)
// Selected database.
_, err = db.Exec("USE to_do_list")
checkErr(err)
// Created table where the data is going to storaged and retrieved.
_, err = db.Exec("CREATE TABLE IF NOT EXISTS tasks (ID tinyint NOT NULL auto_increment, name_task tinytext NOT NULL, description tinytext NOT NULL, responsable tinytext NOT NULL, completed bool not null, primary key (ID))")
checkErr(err)
fmt.Println("")
fmt.Println("WELCOME TO TO_DO_LIST APP BY ZETACODER.")
fmt.Println("CREATE NEW TASKS TO DO, MODIFY IT AND DELETE IT ONCE COMPLETED.ENJOY IT :D")
menu := `
What do you want to do:
(1) NEW TASK.
(2) SHOW ALL.
(3) MODIFY.
(4) COMPLETE.
(5) DELETE.
(6) EXIT APP.
`
// Show menu and depending of the option, execute the CRUD funcs.
for selected_option != 6 {
fmt.Println("")
fmt.Println(menu)
fmt.Scan(&selected_option)
scanner := bufio.NewScanner(os.Stdin)
switch selected_option {
// Create new task
case 1:
fmt.Println("Name of the task:")
if scanner.Scan() {
newTask.Name_task = scanner.Text()
}
fmt.Println("")
fmt.Println("Description:")
if scanner.Scan() {
newTask.Description = scanner.Text()
}
fmt.Println("Person responsable:")
time.Sleep(1 * time.Second)
if scanner.Scan() {
newTask.Responsable = scanner.Text()
}
Create(newTask)
time.Sleep(1 * time.Second)
fmt.Println("TASK ADDED SUCCESFULLY!")
time.Sleep(1 * time.Second)
// Show all tasks
case 2:
tasks, err := Read()
if err != nil {
fmt.Printf("Cant get tasks: %v", err)
} else {
for _, task := range tasks {
fmt.Println("====================")
fmt.Printf("ID: %d\n", task.ID)
fmt.Printf("Name of task: %s\n", task.Name_task)
fmt.Printf("Description: %s\n", task.Description)
fmt.Printf("Responsable: %s\n", task.Responsable)
fmt.Printf("Completed: %v\n", task.Completed)
}
}
case 3:
fmt.Println("Choose the ID of the task to modify:")
fmt.Scanln(&newTask.ID)
fmt.Println("Enter new task name:")
if scanner.Scan() {
newTask.Name_task = scanner.Text()
}
fmt.Println("Enter new description:")
if scanner.Scan() {
newTask.Description = scanner.Text()
}
fmt.Println("Enter the new responsable of the task:")
if scanner.Scan() {
newTask.Responsable = scanner.Text()
}
err := Update(newTask)
if err != nil {
fmt.Printf("Error updating: %v", err)
} else {
time.Sleep(1 * time.Second)
fmt.Println("TASK UPDATED SUCCESFULLY")
time.Sleep(1 * time.Second)
}
case 4:
fmt.Println("Choose the ID of the task you completed:")
fmt.Scanln(&newTask.ID)
Delete(newTask) // Mark as completed
fmt.Printf("Congratulations! Task %d marked as completed", newTask.ID)
time.Sleep(1 * time.Second)
case 5:
fmt.Println("Choose the ID of the task you want to remove:")
fmt.Scanln(&newTask.ID)
Delete(newTask) // task deleted
fmt.Println("Task removed from the list.")
time.Sleep(1 * time.Second)
case 6:
fmt.Println("See ya!")
time.Sleep(1 * time.Second)
os.Exit(0)
}
}
}