diff --git a/go.mod b/go.mod index 980ce1a..43b8ee5 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.22.1 require ( github.com/fatih/color v1.17.0 - github.com/go-playground/validator/v10 v10.17.0 + github.com/go-playground/validator/v10 v10.22.1 github.com/goccy/go-json v0.10.3 github.com/gofiber/contrib/websocket v1.3.0 github.com/gofiber/fiber/v2 v2.52.4 @@ -29,7 +29,7 @@ require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/fasthttp/websocket v1.5.8 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-playground/form v3.1.4+incompatible // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -53,7 +53,7 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.17.8 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 1347db4..0768f7e 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= +github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -50,6 +52,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -159,6 +163,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/pkg/nex/command.go b/pkg/nex/command.go index a87969c..b6df17d 100644 --- a/pkg/nex/command.go +++ b/pkg/nex/command.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc/reflection" "net" "net/http" + "strconv" "strings" "time" ) @@ -70,7 +71,36 @@ func (v localCommandRpcServer) SendCommand(ctx context.Context, argument *proto. } if md, ok := metadata.FromIncomingContext(ctx); ok { for k, v := range md { - cc.values.Store(k, v) + var val any = nil + if len(v) == 1 { + if len(v[0]) != 0 { + if i, err := strconv.ParseInt(v[0], 10, 64); err == nil { + val = i + } else if b, err := strconv.ParseBool(v[0]); err == nil { + val = b + } else if f, err := strconv.ParseFloat(v[0], 64); err == nil { + val = f + } + layouts := []string{ + time.RFC3339, + "2006-01-02 15:04:05", // Example: 2024-10-20 14:55:05 + "2006-01-02", // Example: 2024-10-20 + } + for _, layout := range layouts { + if t, err := time.Parse(layout, v[0]); err == nil { + val = t + } + } + if val == nil { + val = v[0] + } + } else { + val = v[0] + } + } else if len(v) > 1 { + val = v + } + cc.values.Store(k, val) } } if err := handler(cc); err != nil { diff --git a/pkg/nex/cruda/command.go b/pkg/nex/cruda/command.go index aa911c6..8bfd04f 100644 --- a/pkg/nex/cruda/command.go +++ b/pkg/nex/cruda/command.go @@ -3,16 +3,16 @@ package cruda import ( "git.solsynth.dev/hypernet/nexus/pkg/nex" "net/http" - "strconv" ) type CrudAction func(v *CrudConn) nex.CommandHandler func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) error { - funcList := []CrudAction{cmdList[T]} + funcList := []CrudAction{cmdList[T], cmdGet[T], cmdCreate[T], cmdUpdate[T], cmdDelete[T]} funcCmds := []string{".list", ".get", ".create", ".update", ".delete"} + funcMethods := []string{"get", "get", "put", "patch", "delete"} for idx, fn := range funcList { - if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], "get", tags, fn(v)); err != nil { + if err := v.Conn.AddCommand(prefix+id+funcCmds[idx], funcMethods[idx], tags, fn(v)); err != nil { return err } } @@ -21,15 +21,13 @@ func AddModel[T any](v *CrudConn, model T, id, prefix string, tags []string) err func cmdList[T any](c *CrudConn) nex.CommandHandler { return func(ctx *nex.CommandCtx) error { - rawTake := ctx.ValueOrElse("query.take", "10").(string) - rawSkip := ctx.ValueOrElse("query.skip", "0").(string) - take, err := strconv.Atoi(rawTake) - if err != nil { - take = 10 - } - skip, err := strconv.Atoi(rawSkip) - if err != nil { - skip = 0 + take := int(ctx.ValueOrElse("query.take", 10).(int64)) + skip := int(ctx.ValueOrElse("query.skip", 0).(int64)) + + var str T + var count int64 + if err := c.db.Model(str).Count(&count).Error; err != nil { + return err } var out []T @@ -37,6 +35,74 @@ func cmdList[T any](c *CrudConn) nex.CommandHandler { return err } + return ctx.JSON(map[string]any{ + "count": count, + "data": out, + }, http.StatusOK) + } +} + +func cmdGet[T any](c *CrudConn) nex.CommandHandler { + return func(ctx *nex.CommandCtx) error { + id := ctx.ValueOrElse("query.id", 0).(int64) + + var out T + if err := c.db.First(&out, "id = ?", id).Error; err != nil { + return err + } + + return ctx.JSON(out, http.StatusOK) + } +} + +func cmdCreate[T any](c *CrudConn) nex.CommandHandler { + return func(ctx *nex.CommandCtx) error { + var out T + if err := ctx.ReadJSON(&out); err != nil { + return err + } + // TODO validation + + if err := c.db.Create(&out).Error; err != nil { + return err + } + + return ctx.JSON(out, http.StatusOK) + } +} + +func cmdUpdate[T any](c *CrudConn) nex.CommandHandler { + return func(ctx *nex.CommandCtx) error { + id := ctx.ValueOrElse("query.id", 0).(int64) + + var payload T + if err := ctx.ReadJSON(&payload); err != nil { + return err + } + // TODO validation + + var out T + if err := c.db.Model(out).Where("id = ?", id).Updates(&payload).Error; err != nil { + return err + } + + if err := c.db.First(&out, "id = ?", id).Error; err != nil { + return err + } + + return ctx.JSON(out, http.StatusOK) + } +} + +func cmdDelete[T any](c *CrudConn) nex.CommandHandler { + return func(ctx *nex.CommandCtx) error { + id := ctx.ValueOrElse("query.id", 0).(int64) + + var out T + if err := c.db.Delete(&out, "id = ?", id).Error; err != nil { + return err + } + return ctx.JSON(out, http.StatusOK) } }