package todov1 import ( "context" "errors" "log/slog" "strconv" "connectrpc.com/connect" "git.kocoder.xyz/kocoded/vt/fx" todov1 "git.kocoder.xyz/kocoded/vt/gen/todo/v1" "git.kocoder.xyz/kocoded/vt/gen/todo/v1/todov1connect" "git.kocoder.xyz/kocoded/vt/interceptors" "git.kocoder.xyz/kocoded/vt/query" "gorm.io/gen/field" "gorm.io/gorm" ) func NewTodoRoute(db *gorm.DB, logger *slog.Logger, oidcInterceptor *interceptors.AuthenticationInterceptor) fx.Handler { path, handler := todov1connect.NewTodoServiceHandler(&todoService{logger: logger, db: db}, connect.WithInterceptors(oidcInterceptor)) return fx.NewRoute(path, handler) } type todoService struct { logger *slog.Logger db *gorm.DB } func (ts *todoService) GetTodo(ctx context.Context, req *todov1.GetTodosRequest) (*todov1.GetTodosResponse, error) { s, ok := interceptors.SessionFromContext(ctx) if !ok { return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set.")) } t := query.Use(ts.db).Task res, err := t.Where(t.ID.Eq(uint(req.Id))).Where(t.MandantID.Eq(s.MandantId)).First() if err != nil { return nil, connect.NewError(connect.CodeInternal, err) } tres := &todov1.GetTodosResponse{ Id: int64(res.ID), Title: res.Titel, Description: res.Description, Status: todov1.Status(res.Status), } return tres, nil // return &todov1.GetTodosResponse{ // Id: 1, // Title: "Sample Todo", // Description: "This is a sample todo item.", // Status: todov1.Status_Doing, // }, nil } func (ts *todoService) ContributeToQuery(f *todov1.Filter, q query.ITaskDo) query.ITaskDo { t := query.Use(ts.db).Task switch f.Field { case todov1.Field_FieldDescription, todov1.Field_FieldTitle: var field field.String if f.Field == todov1.Field_FieldDescription { field = t.Description } else { field = t.Titel } switch f.Operation { case todov1.Operation_Equals: q = q.Where(field.Eq(f.Value)) case todov1.Operation_NotEquals: q = q.Where(field.Neq(f.Value)) case todov1.Operation_GreaterThan: q = q.Where(field.Gt(f.Value)) case todov1.Operation_LessThan: q = q.Where(field.Lt(f.Value)) case todov1.Operation_Like: q = q.Where(field.Like(f.Value)) } case todov1.Field_FieldId: i, err := strconv.Atoi(f.Value) if err != nil { slog.Warn("Value not an int", "err", err) return q } switch f.Operation { case todov1.Operation_Equals: q = q.Where(t.ID.Eq(uint(i))) case todov1.Operation_NotEquals: q = q.Where(t.ID.Neq(uint(i))) case todov1.Operation_GreaterThan: q = q.Where(t.ID.Gt(uint(i))) case todov1.Operation_LessThan: q = q.Where(t.ID.Lt(uint(i))) } case todov1.Field_FieldStatus: i, err := strconv.Atoi(f.Value) if err != nil { slog.Warn("Value not an int", "err", err) return q } switch f.Operation { case todov1.Operation_Equals: q = q.Where(t.Status.Eq(i)) case todov1.Operation_NotEquals: q = q.Where(t.Status.Neq(i)) case todov1.Operation_GreaterThan: q = q.Where(t.Status.Gt(i)) case todov1.Operation_LessThan: q = q.Where(t.Status.Lt(i)) } default: return q } return q } func (ts *todoService) ListTodos(ctx context.Context, req *todov1.ListTodosRequest) (*todov1.ListTodosResponse, error) { ts.logger.Info("ListTodos called", "request", req) s, ok := interceptors.SessionFromContext(ctx) if !ok { return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("No session set.")) } t := query.Use(ts.db).Task taskQuery := t.Where(t.MandantID.Eq(s.MandantId)) for _, v := range req.Filters { taskQuery = ts.ContributeToQuery(v, taskQuery) } taskQuery = taskQuery.Limit(int(req.PerPage)).Offset(int(req.Page)) if req.OrberBy != "" { f, ok := t.GetFieldByName(req.OrberBy) if ok { if !req.Asc { taskQuery = taskQuery.Order(f.Desc()) } else { taskQuery = taskQuery.Order(f.Asc()) } } } else { taskQuery = taskQuery.Order(t.ID.Asc()) } tasks, err := taskQuery.Find() if err != nil { return nil, err } taskQuery = t.Where(t.MandantID.Eq(s.MandantId)) for _, v := range req.Filters { taskQuery = ts.ContributeToQuery(v, taskQuery) } cnt, err := taskQuery.Count() if err != nil { ts.logger.Info("Counting Todos failed", "request", req, "err", err) panic(err) } data := make([]*todov1.GetTodosResponse, len(tasks)) for i, p := range tasks { data[i] = &todov1.GetTodosResponse{ Id: int64(p.ID), Title: p.Titel, Description: p.Description, Status: todov1.Status(p.Status), } } return &todov1.ListTodosResponse{ Data: data, Meta: &todov1.Metadata{ TotalCount: int32(cnt), }, }, nil }