This commit is contained in:
		| @@ -19,8 +19,8 @@ func NewServer() *HTTPApp { | |||||||
| 	app := fiber.New(fiber.Config{ | 	app := fiber.New(fiber.Config{ | ||||||
| 		DisableStartupMessage: true, | 		DisableStartupMessage: true, | ||||||
| 		EnableIPValidation:    true, | 		EnableIPValidation:    true, | ||||||
| 		ServerHeader:          "Hydrogen.Nexus", | 		ServerHeader:          "Hypernet.Nexus", | ||||||
| 		AppName:               "Hydrogen.Nexus", | 		AppName:               "Hypernet.Nexus", | ||||||
| 		ProxyHeader:           fiber.HeaderXForwardedFor, | 		ProxyHeader:           fiber.HeaderXForwardedFor, | ||||||
| 		JSONEncoder:           json.Marshal, | 		JSONEncoder:           json.Marshal, | ||||||
| 		JSONDecoder:           json.Unmarshal, | 		JSONDecoder:           json.Unmarshal, | ||||||
|   | |||||||
| @@ -1,7 +1,9 @@ | |||||||
| package nex | package nex | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"github.com/goccy/go-json" | 	"github.com/goccy/go-json" | ||||||
|  | 	"net/http" | ||||||
| 	"sync" | 	"sync" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -15,6 +17,28 @@ type CommandCtx struct { | |||||||
| 	values sync.Map | 	values sync.Map | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func CtxValueMustBe[T any](c *CommandCtx, key string) (T, error) { | ||||||
|  | 	if val, ok := c.values.Load(key); ok { | ||||||
|  | 		if v, ok := val.(T); ok { | ||||||
|  | 			return v, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	var out T | ||||||
|  | 	if err := c.Write([]byte(fmt.Sprintf("value %s not found in type %T", key, out)), "text/plain+error", http.StatusBadRequest); err != nil { | ||||||
|  | 		return out, err | ||||||
|  | 	} | ||||||
|  | 	return out, fmt.Errorf("value %s not found", key) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func CtxValueShouldBe[T any](c *CommandCtx, key string, defaultValue T) T { | ||||||
|  | 	if val, ok := c.values.Load(key); ok { | ||||||
|  | 		if v, ok := val.(T); ok { | ||||||
|  | 			return v | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return defaultValue | ||||||
|  | } | ||||||
|  |  | ||||||
| func (c *CommandCtx) Values() map[string]any { | func (c *CommandCtx) Values() map[string]any { | ||||||
| 	duplicate := make(map[string]any) | 	duplicate := make(map[string]any) | ||||||
| 	c.values.Range(func(key, value any) bool { | 	c.values.Range(func(key, value any) bool { | ||||||
|   | |||||||
| @@ -1,8 +0,0 @@ | |||||||
| package nex |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	ServiceTypeAuthProvider        = "auth" |  | ||||||
| 	ServiceTypeFileProvider        = "files" |  | ||||||
| 	ServiceTypeInteractiveProvider = "interactive" |  | ||||||
| 	ServiceTypeMessagingProvider   = "messaging" |  | ||||||
| ) |  | ||||||
| @@ -1,7 +1,10 @@ | |||||||
| package cruda | package cruda | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
| 	"git.solsynth.dev/hypernet/nexus/pkg/nex" | 	"git.solsynth.dev/hypernet/nexus/pkg/nex" | ||||||
|  | 	"github.com/go-playground/validator/v10" | ||||||
|  | 	"gorm.io/gorm" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -9,7 +12,7 @@ type CrudAction func(v *CrudConn) nex.CommandHandler | |||||||
|  |  | ||||||
| func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) error { | func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) error { | ||||||
| 	funcList := []CrudAction{cmdList[T], cmdGet[T], cmdCreate[T], cmdUpdate[T], cmdDelete[T]} | 	funcList := []CrudAction{cmdList[T], cmdGet[T], cmdCreate[T], cmdUpdate[T], cmdDelete[T]} | ||||||
| 	funcCmds := []string{".list", ".get", ".create", ".update", ".delete"} | 	funcCmds := []string{".list", "", "", "", ""} | ||||||
| 	funcMethods := []string{"get", "get", "put", "patch", "delete"} | 	funcMethods := []string{"get", "get", "put", "patch", "delete"} | ||||||
| 	for idx, fn := range funcList { | 	for idx, fn := range funcList { | ||||||
| 		if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], funcMethods[idx], tags, fn(v)); err != nil { | 		if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], funcMethods[idx], tags, fn(v)); err != nil { | ||||||
| @@ -19,10 +22,12 @@ func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) err | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | var validate = validator.New(validator.WithRequiredStructEnabled()) | ||||||
|  |  | ||||||
| func cmdList[T any](c *CrudConn) nex.CommandHandler { | func cmdList[T any](c *CrudConn) nex.CommandHandler { | ||||||
| 	return func(ctx *nex.CommandCtx) error { | 	return func(ctx *nex.CommandCtx) error { | ||||||
| 		take := int(ctx.ValueOrElse("query.take", 10).(int64)) | 		take := int(nex.CtxValueShouldBe[int64](ctx, "query.take", 10)) | ||||||
| 		skip := int(ctx.ValueOrElse("query.skip", 0).(int64)) | 		skip := int(nex.CtxValueShouldBe[int64](ctx, "query.skip", 0)) | ||||||
|  |  | ||||||
| 		var str T | 		var str T | ||||||
| 		var count int64 | 		var count int64 | ||||||
| @@ -44,10 +49,16 @@ func cmdList[T any](c *CrudConn) nex.CommandHandler { | |||||||
|  |  | ||||||
| func cmdGet[T any](c *CrudConn) nex.CommandHandler { | func cmdGet[T any](c *CrudConn) nex.CommandHandler { | ||||||
| 	return func(ctx *nex.CommandCtx) error { | 	return func(ctx *nex.CommandCtx) error { | ||||||
| 		id := ctx.ValueOrElse("query.id", 0).(int64) | 		id, err := nex.CtxValueMustBe[int64](ctx, "query.id") | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var out T | 		var out T | ||||||
| 		if err := c.db.First(&out, "id = ?", id).Error; err != nil { | 		if err := c.db.First(&out, "id = ?", id).Error; err != nil { | ||||||
|  | 			if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|  | 				return ctx.Write([]byte(err.Error()), "text/plain", http.StatusNotFound) | ||||||
|  | 			} | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -57,29 +68,34 @@ func cmdGet[T any](c *CrudConn) nex.CommandHandler { | |||||||
|  |  | ||||||
| func cmdCreate[T any](c *CrudConn) nex.CommandHandler { | func cmdCreate[T any](c *CrudConn) nex.CommandHandler { | ||||||
| 	return func(ctx *nex.CommandCtx) error { | 	return func(ctx *nex.CommandCtx) error { | ||||||
| 		var out T | 		var payload T | ||||||
| 		if err := ctx.ReadJSON(&out); err != nil { | 		if err := ctx.ReadJSON(&payload); err != nil { | ||||||
| 			return err | 			return err | ||||||
|  | 		} else if err := validate.Struct(payload); err != nil { | ||||||
|  | 			return ctx.Write([]byte(err.Error()), "text/plain+error", http.StatusBadRequest) | ||||||
| 		} | 		} | ||||||
| 		// TODO validation |  | ||||||
|  |  | ||||||
| 		if err := c.db.Create(&out).Error; err != nil { | 		if err := c.db.Create(&payload).Error; err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return ctx.JSON(out, http.StatusOK) | 		return ctx.JSON(payload, http.StatusOK) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func cmdUpdate[T any](c *CrudConn) nex.CommandHandler { | func cmdUpdate[T any](c *CrudConn) nex.CommandHandler { | ||||||
| 	return func(ctx *nex.CommandCtx) error { | 	return func(ctx *nex.CommandCtx) error { | ||||||
| 		id := ctx.ValueOrElse("query.id", 0).(int64) | 		id, err := nex.CtxValueMustBe[int64](ctx, "query.id") | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		var payload T | 		var payload T | ||||||
| 		if err := ctx.ReadJSON(&payload); err != nil { | 		if err := ctx.ReadJSON(&payload); err != nil { | ||||||
| 			return err | 			return err | ||||||
|  | 		} else if err := validate.Struct(payload); err != nil { | ||||||
|  | 			return ctx.Write([]byte(err.Error()), "text/plain+error", http.StatusBadRequest) | ||||||
| 		} | 		} | ||||||
| 		// TODO validation |  | ||||||
|  |  | ||||||
| 		var out T | 		var out T | ||||||
| 		if err := c.db.Model(out).Where("id = ?", id).Updates(&payload).Error; err != nil { | 		if err := c.db.Model(out).Where("id = ?", id).Updates(&payload).Error; err != nil { | ||||||
| @@ -96,13 +112,19 @@ func cmdUpdate[T any](c *CrudConn) nex.CommandHandler { | |||||||
|  |  | ||||||
| func cmdDelete[T any](c *CrudConn) nex.CommandHandler { | func cmdDelete[T any](c *CrudConn) nex.CommandHandler { | ||||||
| 	return func(ctx *nex.CommandCtx) error { | 	return func(ctx *nex.CommandCtx) error { | ||||||
| 		id := ctx.ValueOrElse("query.id", 0).(int64) | 		id, err := nex.CtxValueMustBe[int64](ctx, "query.id") | ||||||
|  | 		if err != nil { | ||||||
| 		var out T |  | ||||||
| 		if err := c.db.Delete(&out, "id = ?", id).Error; err != nil { |  | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return ctx.JSON(out, http.StatusOK) | 		var out T | ||||||
|  | 		if err := c.db.Delete(&out, "id = ?", id).Error; err != nil { | ||||||
|  | 			if errors.Is(err, gorm.ErrRecordNotFound) { | ||||||
|  | 				return ctx.Write([]byte(err.Error()), "text/plain", http.StatusNotFound) | ||||||
|  | 			} | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return ctx.Write(nil, "text/plain", http.StatusOK) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ import ( | |||||||
|  |  | ||||||
| type Test struct { | type Test struct { | ||||||
| 	cruda.BaseModel | 	cruda.BaseModel | ||||||
| 	Content string `json:"content"` | 	Content string `json:"content" validate:"required"` | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestCrudaCommand(t *testing.T) { | func TestCrudaCommand(t *testing.T) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user