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

Skills #1

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
NEO4J_URI=neo4j://localhost:7687
NEO4J_USERNAME=
NEO4J_PASSWORD=
CI=true
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
10 changes: 7 additions & 3 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
"go.lintOnSave": "file",
"go.vetOnSave": "package",
"go.coverOnSave": false,
"go.testOnSave": true,
"go.testOnSave": false,
"go.useCodeSnippetsOnFunctionSuggest": false,
"go.buildTags": "",
"go.buildFlags": [],
"go.lintFlags": [],
"go.vetFlags": [],
"go.gopath": "~/projects/go",
"go.goroot": "/usr/local/go",
// WSL
// "go.gopath": "~/projects/go",
// "go.goroot": "/usr/local/go",
// MAC
"go.gopath": "/Users/deo/projects/go",
"go.goroot": "/Users/deo/go",
"go.testTimeout": "30s",
// GOPATH는 프로젝트를 주로 사용하는 경로
// GOROOT는 go가 설치된 경로
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# checkareer-core

## how to run

```bash
make run
```

## performance

```bash
bash contrib/performance.sh
```
3 changes: 3 additions & 0 deletions _test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# \_test

테스트에서 사용할 모듈
67 changes: 19 additions & 48 deletions dbms/neo4j_test.go → _test/_neo4j/modules.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package dbms_test
package _neo4j

import (
"checkareer-core/_test"
"checkareer-core/config"
"checkareer-core/dbms"
"context"
"fmt"
"log"
"testing"

"github.com/neo4j/neo4j-go-driver/v4/neo4j"
"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
"go.uber.org/fx"
Expand All @@ -19,6 +16,7 @@ import (
// registerHook invoke로 호출되므로 파라미터의 순서가 초기화의 순서
func registerHook(
lifecycle fx.Lifecycle,
settings *config.Settings,
neo4jContainer testcontainers.Container,
driver neo4j.Driver,
) {
Expand All @@ -28,12 +26,19 @@ func registerHook(
if err != nil {
fmt.Println(err)
}
return neo4jContainer.Terminate(context)
if settings.CI {
return neo4jContainer.Terminate(context)
}
return err
},
})
}

// NewNeo4jTestContainer for neo4j test
func NewNeo4jTestContainer(settings *config.Settings) testcontainers.Container {
if !settings.CI {
return nil
}
ctx := context.Background()
container, err := startContainer(ctx, settings.Neo4j.Username, settings.Neo4j.Password)
if err != nil {
Expand Down Expand Up @@ -65,14 +70,18 @@ func startContainer(
})
}

// NewSettings constructor
func NewSettings() *config.Settings {
var settings config.Settings
settings.Neo4j.URI = ""
settings.Neo4j.Username = "neo4j"
settings.Neo4j.Password = "t2st2r"
return &settings
settings := config.NewSettings()

if settings.CI {
settings.Neo4j.Username = "neo4j"
settings.Neo4j.Password = "t2st2r"
}
return settings
}

// TestModules of neo4j
var TestModules = fx.Options(
fx.Provide(
dbms.NewNeo4jDriver,
Expand All @@ -82,41 +91,3 @@ var TestModules = fx.Options(
),
fx.Invoke(registerHook),
)

func TestCreateCyper(t *testing.T) {
f := func(settings *config.Settings, generator dbms.Neo4jSessionGenerator) {
session := generator()
defer session.Close()
result, err := session.WriteTransaction(createItem)
assert.NoError(t, err)
assert.NotNil(t, result)
}
app := _test.NewForTest(t, TestModules, fx.Invoke(f))
app.RequireStart()
}

func createItem(tx neo4j.Transaction) (interface{}, error) {
records, err := tx.Run(
"MERGE (n: Item {id: $id, name: $name}) RETURN n.id, n.name",
map[string]interface{}{
"id": 1, "name": "Item 1",
},
)
if err != nil {
return nil, err
}
record, err := records.Single()
if err != nil {
return nil, err
}
return &Item{
ID: record.Values[0].(int64),
Name: record.Values[1].(string),
}, nil
}

// Item
type Item struct {
ID int64
Name string
}
14 changes: 14 additions & 0 deletions api/modules.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package api

import (
"checkareer-core/api/v1/skills"

"go.uber.org/fx"
)

// Modules of skills
var Modules = fx.Options(
fx.Provide(NewServer),
fx.Provide(skills.NewHandler),
fx.Invoke(registerHook, skills.BindRoutes),
)
46 changes: 46 additions & 0 deletions api/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package api

import (
"checkareer-core/config"
"context"
"fmt"
"log"

"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
echoSwagger "github.com/swaggo/echo-swagger"

"go.uber.org/fx"
)

// NewServer creates a new server.
func NewServer(settings *config.Settings) *echo.Echo {
e := echo.New()
e.Use(
middleware.Recover(),
middleware.RequestID(),
)
e.GET("/swagger/*", echoSwagger.WrapHandler)
e.Validator = &RequestValidator{validator: validator.New()}

return e
}

func registerHook(lifecycle fx.Lifecycle, server *echo.Echo, settings *config.Settings) {
lifecycle.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
go func() {
err := server.Start(settings.BindAddress())
if err != nil {
log.Fatal(err)
}
}()
return nil
},
OnStop: func(ctx context.Context) error {
fmt.Println("Stopping Http Server.")
return server.Shutdown(ctx)
},
})
}
94 changes: 94 additions & 0 deletions api/v1/skills/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package skills

import (
"checkareer-core/modules/skills"
"net/http"

"github.com/labstack/echo/v4"
)

type (
// Handler 스킬 핸들러
Handler interface {
Get(context echo.Context) error
Post(context echo.Context) error
Patch(context echo.Context) error
Delete(context echo.Context) error
}
handler struct {
skills.Creater
skills.Reader
skills.Updater
skills.Deleter
}
)

// NewHandler 스킬 핸들러 생성
func NewHandler(
creater skills.Creater,
reader skills.Reader,
updater skills.Updater,
deleter skills.Deleter,
) Handler {
return &handler{
creater,
reader,
updater,
deleter,
}
}

// BindRoutes 스킬 핸들러에 라우팅 정보 바인딩
func BindRoutes(server *echo.Echo, handler Handler) {
group := server.Group("/v1/skills")
group.GET("", handler.Get)
group.POST("", handler.Post)
group.PATCH("/:id", handler.Patch)
group.DELETE("/:id", handler.Delete)
}

// Get 스킬 조회
// @ID skills-get
// @Tags skills
// @Summary skills get
// @Description skills get
// @Router /v1/skills [get]
// @Param _ query Params true "params"
// @Security ApiKeyAuth
// @Produce json
// @Success 200 {object} ManyItemResponse
// @Failure 400 {object} interface{}
// @Failure 500 {object} interface{}
func (h handler) Get(context echo.Context) error {
var param Params
if err := context.Bind(&param); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
if err := context.Validate(&param); err != nil {
return err
}
_skills, err := h.Read(skills.WithID(param.ID), skills.WithLimit(param.Limit))
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
response := ManyItemResponse{
Skills: _skills,
Limit: param.Limit,
}
return context.JSON(http.StatusOK, response)
}

// Post 스킬 생성
func (h handler) Post(context echo.Context) error {
return nil
}

// Patch 스킬 수정
func (h handler) Patch(context echo.Context) error {
return nil
}

// Delete 스킬 삭제
func (h handler) Delete(context echo.Context) error {
return nil
}
7 changes: 7 additions & 0 deletions api/v1/skills/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package skills

// Params of skills
type Params struct {
ID int64 `query:"id" json:"id,omitempty" validate:"gte=0"`
Limit uint `query:"limit" json:"limit,omitempty" validate:"gte=1" default:"25" example:"25"`
}
9 changes: 9 additions & 0 deletions api/v1/skills/response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package skills

import "checkareer-core/modules/skills"

// ManyItemResponse 여러 개의 아이템을 반환하는 응답
type ManyItemResponse struct {
Skills []skills.Node `json:"skills"`
Limit uint `json:"limit"`
}
27 changes: 27 additions & 0 deletions api/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package api

import (
"net/http"

"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
)

// RequestValidator HTTP 요청에 대한 validator
// https://echo.labstack.com/guide/request/#validate-data
type RequestValidator struct {
validator *validator.Validate
}

// NewRequestValidator validator 생성자
func NewRequestValidator(validator *validator.Validate) *RequestValidator {
return &RequestValidator{validator: validator}
}

// Validate 유효성 검사 함수
func (v *RequestValidator) Validate(i interface{}) error {
if err := v.validator.Struct(i); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
return nil
}
9 changes: 7 additions & 2 deletions cmd/run.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package cmd

import (
"checkareer-core/api"
"checkareer-core/config"
"checkareer-core/dbms"
"checkareer-core/modules/skills"
"fmt"

"github.com/spf13/cobra"
Expand All @@ -13,10 +16,12 @@ var runCmd = &cobra.Command{
Version: Version,
Short: fmt.Sprintf("%s Run", Name),
Run: func(cmd *cobra.Command, args []string) {
f := func() {
}
f := func() {}
modules := fx.Options(
config.Modules,
dbms.Modules,
skills.Modules,
api.Modules,
fx.Invoke(f),
)
fx.New(modules).Run()
Expand Down
Loading