Skip to content

Commit

Permalink
Add basic problem service (#16)
Browse files Browse the repository at this point in the history
* Add problem mapper

* Add problem option search test

* Move service code

* Problem router & service
  • Loading branch information
akamya997 authored Sep 3, 2023
1 parent 2c2aac3 commit e1dd054
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 20 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build:
@echo "Building on $(OS)"
go mod tidy
go build -o bin/migrate_db migration/migrate_db.go
go build -o bin/user_service user-service/application.go
go build -o bin/service service/application.go

.PHONY: clear-db
clear-db:
Expand All @@ -29,7 +29,7 @@ test: build check setup-db

.PHONY: run
run: build check setup-db
./bin/user_service
./bin/service

.PHONY: help
help:
Expand Down
102 changes: 102 additions & 0 deletions packages/mapper/problem.go
Original file line number Diff line number Diff line change
@@ -1 +1,103 @@
package mapper

import (
"github.com/OJ-lab/oj-lab-services/packages/application"
"github.com/OJ-lab/oj-lab-services/packages/model"
)

func CreateProblem(problem model.Problem) error {
db := application.GetDefaultDB()
return db.Create(&problem).Error
}

func GetProblem(slug string) (model.Problem, error) {
db := application.GetDefaultDB()
db_problem := model.Problem{}
err := db.Model(&model.Problem{}).Preload("Tags").Where("Slug = ?", slug).First(&db_problem).Error
return db_problem, err
}

func DeleteProblem(problem model.Problem) error {
db := application.GetDefaultDB()
return db.Delete(&model.Problem{Slug: problem.Slug}).Error
}

func UpdateProblem(problem model.Problem) error {
db := application.GetDefaultDB()
return db.Model(&model.Problem{Slug: problem.Slug}).Updates(problem).Error
}

type GetProblemOptions struct {
Slug string
Title string
Tags []*model.AlgorithmTag
Offset *int
Limit *int
}

func CountProblemByOptions(options GetProblemOptions) (int64, error) {
db := application.GetDefaultDB()
var count int64

tagsList := []string{}
for _, tag := range options.Tags {
tagsList = append(tagsList, tag.Slug)
}

tx := db.
Model(&model.Problem{}).
Joins("JOIN problem_algorithm_tags ON problem_algorithm_tags.problem_slug = problems.slug").
Where("problem_algorithm_tags.algorithm_tag_slug in ?", tagsList).
Or("Slug = ?", options.Slug).
Or("Title = ?", options.Title).
Distinct().
Preload("Tags")

err := tx.Count(&count).Error

return count, err
}

func GetProblemByOptions(options GetProblemOptions) ([]model.Problem, int64, error) {
total, err := CountProblemByOptions(options)
if err != nil {
return nil, 0, err
}

db := application.GetDefaultDB()
db_problems := []model.Problem{}
tagsList := []string{}
for _, tag := range options.Tags {
tagsList = append(tagsList, tag.Slug)
}
tx := db.
Model(&model.Problem{}).
Joins("JOIN problem_algorithm_tags ON problem_algorithm_tags.problem_slug = problems.slug").
Where("problem_algorithm_tags.algorithm_tag_slug in ?", tagsList).
Or("Slug = ?", options.Slug).
Or("Title = ?", options.Title).
Distinct().
Preload("Tags")

if options.Offset != nil {
tx = tx.Offset(*options.Offset)
}
if options.Limit != nil {
tx = tx.Limit(*options.Limit)
}

err = tx.Find(&db_problems).Error
if err != nil {
return nil, 0, err
}

return db_problems, total, nil
}

func GetTagsList(problem model.Problem) []string {
tagsList := []string{}
for _, tag := range problem.Tags {
tagsList = append(tagsList, tag.Slug)
}
return tagsList
}
54 changes: 54 additions & 0 deletions packages/mapper/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package mapper

import (
"encoding/json"
"fmt"
"testing"

"github.com/OJ-lab/oj-lab-services/packages/model"
)

func TestProblemMapper(t *testing.T) {
problem := model.Problem{
Slug: "a+b-problem",
Title: "A+B Problem",
Description: "Given two integer A and B, please output the answer of A+B.",
Tags: []*model.AlgorithmTag{{Slug: "tag1"}, {Slug: "tag2"}},
}
err := CreateProblem(problem)
if err != nil {
t.Error(err)
}

dbProblem, err := GetProblem(problem.Slug)
if err != nil {
t.Error(err)
}

problemJson, err := json.MarshalIndent(dbProblem, "", "\t")
if err != nil {
t.Error(err)
}
fmt.Printf("%+v\n", string(problemJson))

problemOption := GetProblemOptions{
Slug: "",
Title: "",
Tags: []*model.AlgorithmTag{{Slug: "tag1"}},
}

dbProblems, problemCount, err := GetProblemByOptions(problemOption)
if err != nil {
t.Error(err)
}
fmt.Printf("problemCount: %d\n", problemCount)
if problemCount != 1 {
t.Error("problemCount should be 1")
}

problemsJson, err := json.MarshalIndent(dbProblems, "", "\t")
if err != nil {
t.Error(err)
}
fmt.Printf("%+v\n", string(problemsJson))
}
2 changes: 1 addition & 1 deletion packages/model/problem.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type Problem struct {
MetaFields
Slug string `gorm:"primaryKey"`
Title string `gorm:"not null"`
Discription string `gorm:"not null"`
Description string `gorm:"not null"`
Tags []*AlgorithmTag `gorm:"many2many:problem_algorithm_tags;"`
}

Expand Down
3 changes: 2 additions & 1 deletion user-service/application.go → service/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package main

import (
"github.com/OJ-lab/oj-lab-services/packages/application"
"github.com/OJ-lab/oj-lab-services/user-service/router"
"github.com/OJ-lab/oj-lab-services/service/router"
"github.com/gin-gonic/gin"
)

Expand All @@ -25,6 +25,7 @@ func main() {
r := gin.Default()
gin.SetMode(serviceMode)
router.SetupUserRouter(r)
router.SetupProblemRoute(r)

err := r.Run(servicePort)
if err != nil {
Expand Down
23 changes: 23 additions & 0 deletions service/problem/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package problem

import (
"github.com/OJ-lab/oj-lab-services/packages/mapper"
"github.com/OJ-lab/oj-lab-services/packages/utils"
"github.com/gin-gonic/gin"
)

func GetProblemInfo(c *gin.Context) {
slug := c.Param("slug")
problem, err := mapper.GetProblem(slug)
if err != nil {
utils.ApplyError(c, err)
return
}

c.JSON(200, gin.H{
"slug": problem.Slug,
"title": problem.Title,
"description": problem.Description,
"tags": mapper.GetTagsList(problem),
})
}
27 changes: 27 additions & 0 deletions service/router/setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package router

import (
"net/http"

"github.com/OJ-lab/oj-lab-services/service/problem"
"github.com/gin-gonic/gin"
)

func SetupUserRouter(r *gin.Engine) {
g := r.Group("/api/user")
{
g.GET("/health", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, this is user service")
})
}
}

func SetupProblemRoute(r *gin.Engine) {
g := r.Group("/api/v1/problem")
{
g.GET("/health", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, this is problem service")
})
g.GET("/:slug", problem.GetProblemInfo)
}
}
16 changes: 0 additions & 16 deletions user-service/router/setup.go

This file was deleted.

0 comments on commit e1dd054

Please sign in to comment.