Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Database to PostgreSQL #26

Merged
merged 12 commits into from
Apr 19, 2024
8 changes: 8 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DB_PATH=
STATIC_FILES_URL=
WEBHOOK_URL=
DB_HOST=
DB_PORT=
DB_USER=
DB_PASSWORD=
DB_NAME=
4 changes: 4 additions & 0 deletions backend/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
metaploy-network:
aliases:
- iqps-backend
metaploy-private-network:
volumes:
- ./db:/db
- nginx-config-volume:/etc/nginx/sites-enabled
Expand All @@ -15,6 +16,9 @@ networks:
metaploy-network:
external: true
name: metaploy-network
metaploy-private-network:
external: true
name: metaploy-private-network

volumes:
nginx-config-volume:
Expand Down
3 changes: 2 additions & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21.6

require (
github.com/joho/godotenv v1.5.1
github.com/mattn/go-sqlite3 v1.14.22
github.com/rs/cors v1.10.1
)

require github.com/lib/pq v1.10.9
4 changes: 2 additions & 2 deletions backend/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
82 changes: 45 additions & 37 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,36 @@ import (
"github.com/joho/godotenv"
"github.com/rs/cors"

_ "github.com/mattn/go-sqlite3"
_ "github.com/lib/pq"
)

type QuestionPaper struct {
ID int `json:"id"`
CourseCode string `json:"course_code"`
CourseName string `json:"course_name"`
Year int `json:"year"`
Exam string `json:"exam"`
FileLink string `json:"filelink"`
FromLibrary bool `json:"from_library"`
ID int `json:"id"`
CourseCode string `json:"course_code"`
CourseName string `json:"course_name"`
Year int `json:"year"`
Exam string `json:"exam"`
FileLink string `json:"filelink"`
FromLibrary bool `json:"from_library"`
UploadTimestamp string `json:"upload_timestamp"`
ApproveStatus bool `json:"approve_status"`
}

var (
db *sql.DB
staticFilesUrl string
)

const init_db = `
CREATE TABLE IF NOT EXISTS qp (
id INTEGER PRIMARY KEY,
course_code TEXT NOT NULL DEFAULT '',
course_name TEXT NOT NULL,
year INTEGER NOT NULL,
exam TEXT CHECK (exam IN ('midsem', 'endsem') OR exam = '') DEFAULT '',
filelink TEXT NOT NULL,
from_library BOOLEAN DEFAULT 0
const init_db = `CREATE TABLE IF NOT EXISTS qp (
id SERIAL PRIMARY KEY,
course_code TEXT NOT NULL DEFAULT '',
course_name TEXT NOT NULL,
year INTEGER NOT NULL,
exam TEXT CHECK (exam IN ('midsem', 'endsem') OR exam = ''),
filelink TEXT NOT NULL,
from_library BOOLEAN DEFAULT FALSE,
upload_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
approve_status BOOLEAN DEFAULT FALSE
);
`

Expand Down Expand Up @@ -103,24 +106,16 @@ func search(w http.ResponseWriter, r *http.Request) {
http.Error(w, "course is required", http.StatusBadRequest)
return
}
query := `SELECT * FROM qp WHERE rowid IN (SELECT rowid FROM qp_better WHERE course_name MATCH ?)`

// query := `SELECT id,course_code,course_name,year,exam,filelink,from_library,upload_timestamp,approve_status FROM qp WHERE course_code_tsvector @@ websearch_to_tsquery('english', $1)`
query := `SELECT * FROM (SELECT id,course_code,course_name,year,exam,filelink,from_library,upload_timestamp,approve_status FROM qp WHERE course_code_tsvector @@ websearch_to_tsquery('simple', $1) UNION SELECT id,course_code,course_name,year,exam,filelink,from_library,upload_timestamp,approve_status from qp where course_code %>> $1 UNION SELECT id,course_code,course_name,year,exam,filelink,from_library,upload_timestamp,approve_status from qp where course_code_tsvector @@ to_tsquery('simple', $1 ||':*'))`

var params []interface{}
params = append(params, course)

year := r.URL.Query().Get("year")
if year != "" {
yearInt, err := strconv.Atoi(year)
if err != nil {
http.Error(w, "year must be a number", http.StatusBadRequest)
return
}
query = fmt.Sprintf(`%s AND year = ?`, query)
params = append(params, strconv.Itoa(yearInt))
}

exam := r.URL.Query().Get("exam")
if exam != "" {
query = fmt.Sprintf(`%s AND (exam = ? OR exam = '')`, query)
query = fmt.Sprintf(`%s WHERE (exam = $2 OR exam = '')`, query)
params = append(params, exam)
}

Expand All @@ -134,7 +129,7 @@ func search(w http.ResponseWriter, r *http.Request) {
var qps []QuestionPaper = make([]QuestionPaper, 0)
for rows.Next() {
qp := QuestionPaper{}
err := rows.Scan(&qp.ID, &qp.CourseCode, &qp.CourseName, &qp.Year, &qp.Exam, &qp.FileLink, &qp.FromLibrary)
err := rows.Scan(&qp.ID, &qp.CourseCode, &qp.CourseName, &qp.Year, &qp.Exam, &qp.FileLink, &qp.FromLibrary, &qp.UploadTimestamp, &qp.ApproveStatus)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Expand All @@ -151,23 +146,36 @@ func search(w http.ResponseWriter, r *http.Request) {
}
}

func CheckError(err error) {
if err != nil {
panic(err)
}
}

func main() {
err := godotenv.Load(".env")
if err != nil {
log.Fatal(err)
}

dbPath := os.Getenv("DB_PATH")
host := os.Getenv("DB_HOST")
port, err := strconv.Atoi(os.Getenv("DB_PORT"))
CheckError(err)
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
dbname := os.Getenv("DB_NAME")

staticFilesUrl = os.Getenv("STATIC_FILES_URL")

db, err = sql.Open("sqlite3", dbPath)

if err != nil {
log.Fatal(err)
}
psqlconn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)

db, err = sql.Open("postgres", psqlconn)
CheckError(err)
defer db.Close()

err = db.Ping()
CheckError(err)

_, err = db.Exec(init_db)
if err != nil {
log.Fatal(err)
Expand Down
4 changes: 3 additions & 1 deletion backend/search.sql
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
CREATE VIRTUAL TABLE qp_better USING fts5(course_name, tokenize="porter ascii");
INSERT INTO qp_better SELECT course_name FROM qp;
INSERT INTO qp_better SELECT course_name FROM qp;

CREATE VIRTUAL TABLE qp_better2 USING fts5(course_name, tokenize='trigram');
2 changes: 2 additions & 0 deletions backend/sql/indexes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE qp ADD COLUMN course_code_tsvector tsvector GENERATED ALWAYS AS (to_tsvector('english', course_code)) STORED;
CREATE INDEX idx_course_code_tsvector ON qp USING GIN (course_code_tsvector);
11 changes: 11 additions & 0 deletions backend/sql/init_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS qp (
id SERIAL PRIMARY KEY,
course_code TEXT NOT NULL DEFAULT '',
course_name TEXT NOT NULL,
year INTEGER NOT NULL,
exam TEXT CHECK (exam IN ('midsem', 'endsem') OR exam = ''),
filelink TEXT NOT NULL,
from_library BOOLEAN DEFAULT FALSE,
upload_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
approve_status BOOLEAN DEFAULT FALSE
);