go-duck-cli 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ package controllers
3
3
  import (
4
4
  "net/http"
5
5
  "strconv"
6
+ "strings"
6
7
  {{#if isSearchable}}
7
8
  "context"
8
9
  {{/if}}
@@ -22,6 +23,8 @@ import (
22
23
  "{{app_name}}/internal/search"
23
24
  {{/if}}
24
25
  "github.com/gin-gonic/gin"
26
+ "github.com/gin-gonic/gin/binding"
27
+ "github.com/gin-gonic/gin/render"
25
28
  {{#if isDocument}}
26
29
  "go.mongodb.org/mongo-driver/bson"
27
30
  "go.mongodb.org/mongo-driver/mongo"
@@ -44,9 +47,16 @@ type {{capitalize name}}Controller struct {
44
47
  func (ctrl *{{capitalize name}}Controller) Create(c *gin.Context) {
45
48
  ctx := c.Request.Context()
46
49
  var entity models.{{capitalize name}}
47
- if err := c.ShouldBindJSON(&entity); err != nil {
48
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
49
- return
50
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
51
+ if err := c.ShouldBindWith(&entity, binding.MsgPack); err != nil {
52
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
53
+ return
54
+ }
55
+ } else {
56
+ if err := c.ShouldBindJSON(&entity); err != nil {
57
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
58
+ return
59
+ }
50
60
  }
51
61
 
52
62
  {{#if isDocument}}
@@ -138,7 +148,11 @@ func (ctrl *{{capitalize name}}Controller) Create(c *gin.Context) {
138
148
  }
139
149
  {{/if}}
140
150
 
141
- c.JSON(http.StatusCreated, entity)
151
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
152
+ c.Render(http.StatusCreated, render.MsgPack{Data: entity})
153
+ } else {
154
+ c.JSON(http.StatusCreated, entity)
155
+ }
142
156
  }
143
157
 
144
158
  // GetAll handles parallel read aggregation for both SQL and Mongo
@@ -146,6 +160,7 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
146
160
  ctx := c.Request.Context()
147
161
  page, _ := strconv.Atoi(c.DefaultQuery("page", "0"))
148
162
  size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
163
+ sortParam := c.DefaultQuery("sort", "")
149
164
 
150
165
  offset := 0
151
166
  if page > 0 {
@@ -169,6 +184,15 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
169
184
  defer wg.Done()
170
185
  var entities []models.{{capitalize name}}
171
186
  opts := options.Find().SetSkip(int64(offset)).SetLimit(int64(size))
187
+ if sortParam != "" {
188
+ parts := strings.Split(sortParam, ",")
189
+ field := parts[0]
190
+ order := 1
191
+ if len(parts) > 1 && strings.ToLower(parts[1]) == "desc" {
192
+ order = -1
193
+ }
194
+ opts.SetSort(bson.D{bson.E{Key: field, Value: order}})
195
+ }
172
196
  cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
173
197
  if err == nil {
174
198
  cursor.All(ctx, &entities)
@@ -179,7 +203,11 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
179
203
  }(role, siloDB)
180
204
  }
181
205
  wg.Wait()
182
- c.JSON(http.StatusOK, federatedData)
206
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
207
+ c.Render(http.StatusOK, render.MsgPack{Data: federatedData})
208
+ } else {
209
+ c.JSON(http.StatusOK, federatedData)
210
+ }
183
211
  return
184
212
  }
185
213
  {{/if}}
@@ -200,13 +228,26 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
200
228
 
201
229
  var entities []models.{{capitalize name}}
202
230
  opts := options.Find().SetSkip(int64(offset)).SetLimit(int64(size))
231
+ if sortParam != "" {
232
+ parts := strings.Split(sortParam, ",")
233
+ field := parts[0]
234
+ order := 1
235
+ if len(parts) > 1 && strings.ToLower(parts[1]) == "desc" {
236
+ order = -1
237
+ }
238
+ opts.SetSort(bson.D{bson.E{Key: field, Value: order}})
239
+ }
203
240
  cursor, err := tenantDB.Collection("{{toLowerCase name}}s").Find(ctx, filter, opts)
204
241
  if err != nil {
205
242
  c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
206
243
  return
207
244
  }
208
245
  cursor.All(ctx, &entities)
209
- c.JSON(http.StatusOK, entities)
246
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
247
+ c.Render(http.StatusOK, render.MsgPack{Data: entities})
248
+ } else {
249
+ c.JSON(http.StatusOK, entities)
250
+ }
210
251
 
211
252
  {{else}}
212
253
  // 🦆 GORM Path
@@ -227,7 +268,11 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
227
268
  go func(r string, db *gorm.DB) {
228
269
  defer wg.Done()
229
270
  var entities []models.{{capitalize name}}
230
- if err := db.WithContext(ctx).Offset(offset).Limit(size).Find(&entities).Error; err == nil {
271
+ query := db.WithContext(ctx)
272
+ if sortParam != "" {
273
+ query = query.Order(strings.ReplaceAll(sortParam, ",", " "))
274
+ }
275
+ if err := query.Offset(offset).Limit(size).Find(&entities).Error; err == nil {
231
276
  mu.Lock()
232
277
  federatedData[r] = entities
233
278
  mu.Unlock()
@@ -235,7 +280,11 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
235
280
  }(role, siloDB)
236
281
  }
237
282
  wg.Wait()
238
- c.JSON(http.StatusOK, federatedData)
283
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
284
+ c.Render(http.StatusOK, render.MsgPack{Data: federatedData})
285
+ } else {
286
+ c.JSON(http.StatusOK, federatedData)
287
+ }
239
288
  return
240
289
  }
241
290
  {{/if}}
@@ -248,11 +297,19 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
248
297
  c.Header("X-Total-Count", strconv.FormatInt(totalCount, 10))
249
298
 
250
299
  var entities []models.{{capitalize name}}
251
- if err := tenantDB.WithContext(ctx).Offset(offset).Limit(size).Find(&entities).Error; err != nil {
300
+ query := tenantDB.WithContext(ctx)
301
+ if sortParam != "" {
302
+ query = query.Order(strings.ReplaceAll(sortParam, ",", " "))
303
+ }
304
+ if err := query.Offset(offset).Limit(size).Find(&entities).Error; err != nil {
252
305
  c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
253
306
  return
254
307
  }
255
- c.JSON(http.StatusOK, entities)
308
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
309
+ c.Render(http.StatusOK, render.MsgPack{Data: entities})
310
+ } else {
311
+ c.JSON(http.StatusOK, entities)
312
+ }
256
313
  {{/if}}
257
314
  }
258
315
 
@@ -269,7 +326,11 @@ func (ctrl *{{capitalize name}}Controller) GetByID(c *gin.Context) {
269
326
  c.JSON(http.StatusNotFound, gin.H{"error": "Not found"})
270
327
  return
271
328
  }
272
- c.JSON(http.StatusOK, entity)
329
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
330
+ c.Render(http.StatusOK, render.MsgPack{Data: entity})
331
+ } else {
332
+ c.JSON(http.StatusOK, entity)
333
+ }
273
334
  {{else}}
274
335
  db, _ := c.Get("tenantDBConn")
275
336
  tenantDB := db.(*gorm.DB)
@@ -278,7 +339,11 @@ func (ctrl *{{capitalize name}}Controller) GetByID(c *gin.Context) {
278
339
  c.JSON(http.StatusNotFound, gin.H{"error": "Not found"})
279
340
  return
280
341
  }
281
- c.JSON(http.StatusOK, entity)
342
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
343
+ c.Render(http.StatusOK, render.MsgPack{Data: entity})
344
+ } else {
345
+ c.JSON(http.StatusOK, entity)
346
+ }
282
347
  {{/if}}
283
348
  }
284
349
 
@@ -286,9 +351,16 @@ func (ctrl *{{capitalize name}}Controller) Update(c *gin.Context) {
286
351
  ctx := c.Request.Context()
287
352
  id := c.Param("id")
288
353
  var entity models.{{capitalize name}}
289
- if err := c.ShouldBindJSON(&entity); err != nil {
290
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
291
- return
354
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
355
+ if err := c.ShouldBindWith(&entity, binding.MsgPack); err != nil {
356
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
357
+ return
358
+ }
359
+ } else {
360
+ if err := c.ShouldBindJSON(&entity); err != nil {
361
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
362
+ return
363
+ }
292
364
  }
293
365
 
294
366
  {{#if isDocument}}
@@ -320,7 +392,11 @@ func (ctrl *{{capitalize name}}Controller) Update(c *gin.Context) {
320
392
  messaging.PublishEvent(ctrl.Config.GoDuck.Messaging.MQTT.TopicPrefix, "tenant", "UPDATE", "{{capitalize name}}", entity, nil)
321
393
  {{/if}}
322
394
 
323
- c.JSON(http.StatusOK, entity)
395
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
396
+ c.Render(http.StatusOK, render.MsgPack{Data: entity})
397
+ } else {
398
+ c.JSON(http.StatusOK, entity)
399
+ }
324
400
  }
325
401
 
326
402
  func (ctrl *{{capitalize name}}Controller) Delete(c *gin.Context) {
@@ -356,9 +432,16 @@ func (ctrl *{{capitalize name}}Controller) Patch(c *gin.Context) {
356
432
  ctx := c.Request.Context()
357
433
  id := c.Param("id")
358
434
  var updates map[string]interface{}
359
- if err := c.ShouldBindJSON(&updates); err != nil {
360
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
361
- return
435
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
436
+ if err := c.ShouldBindWith(&updates, binding.MsgPack); err != nil {
437
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
438
+ return
439
+ }
440
+ } else {
441
+ if err := c.ShouldBindJSON(&updates); err != nil {
442
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
443
+ return
444
+ }
362
445
  }
363
446
 
364
447
  {{#if isDocument}}
@@ -383,7 +466,11 @@ func (ctrl *{{capitalize name}}Controller) Patch(c *gin.Context) {
383
466
  messaging.PublishEvent(ctrl.Config.GoDuck.Messaging.MQTT.TopicPrefix, "tenant", "PATCH", "{{capitalize name}}", updates, nil)
384
467
  {{/if}}
385
468
 
386
- c.JSON(http.StatusOK, gin.H{"message": "Patch successful"})
469
+ if ctrl.Config.GoDuck.Server.REST.Protocol == "messagepack" {
470
+ c.Render(http.StatusOK, render.MsgPack{Data: gin.H{"message": "Patch successful"}})
471
+ } else {
472
+ c.JSON(http.StatusOK, gin.H{"message": "Patch successful"})
473
+ }
387
474
  }
388
475
 
389
476
  func (ctrl *{{capitalize name}}Controller) BulkCreate(c *gin.Context) { c.JSON(http.StatusNotImplemented, gin.H{"error": "Bulk operations use primary silo isolation by default."}) }
@@ -14,6 +14,8 @@ import (
14
14
  "{{app_name}}/integrations/wso2"
15
15
  "gorm.io/driver/postgres"
16
16
  "gorm.io/gorm"
17
+ "net/http"
18
+ "github.com/improbable-eng/grpc-web/go/grpcweb"
17
19
  )
18
20
 
19
21
  func main() {
@@ -40,6 +42,18 @@ func main() {
40
42
  go func() {
41
43
  grpcSrv := server.NewGRPCServer(appConfig, repo)
42
44
  logger.Info("Starting Kratos gRPC server on %s", appConfig.GoDuck.Server.GRPC.Addr)
45
+
46
+ if appConfig.GoDuck.Server.GRPC.WebEnabled {
47
+ wrappedGrpc := grpcweb.WrapServer(grpcSrv.Server)
48
+ go func() {
49
+ webPort := fmt.Sprintf(":%d", appConfig.GoDuck.Server.GRPC.WebPort)
50
+ logger.Info("Starting gRPC-Web Proxy on %s", webPort)
51
+ if err := http.ListenAndServe(webPort, wrappedGrpc); err != nil {
52
+ logger.Error("Failed to start gRPC-Web Proxy: %v", err)
53
+ }
54
+ }()
55
+ }
56
+
43
57
  if err := grpcSrv.Start(context.Background()); err != nil {
44
58
  logger.Error("Failed to start Kratos gRPC server: %v", err)
45
59
  }
@@ -56,7 +70,7 @@ func main() {
56
70
  }
57
71
 
58
72
  // 6. Start HTTP Server
59
- port := fmt.Sprintf(":%d", appConfig.GoDuck.Server.Port)
60
- logger.Info("Starting HTTP server on %s", port)
73
+ port := fmt.Sprintf(":%d", appConfig.GoDuck.Server.REST.Port)
74
+ logger.Info("Starting HTTP REST server on %s", port)
61
75
  r.Run(port)
62
76
  }
@@ -2,6 +2,7 @@ package service
2
2
 
3
3
  import (
4
4
  "context"
5
+ "strings"
5
6
  {{#if needFmt}}
6
7
  "fmt"
7
8
  {{/if}}
@@ -283,6 +284,15 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
283
284
  for role, db := range siloConns {
284
285
  var results []models.{{capitalize name}}
285
286
  opts := options.Find().SetSkip(int64((req.Page - 1) * req.PageSize)).SetLimit(int64(req.PageSize))
287
+ if req.Sort != "" {
288
+ parts := strings.Split(req.Sort, ",")
289
+ field := parts[0]
290
+ order := 1
291
+ if len(parts) > 1 && strings.ToLower(parts[1]) == "desc" {
292
+ order = -1
293
+ }
294
+ opts.SetSort(bson.D{bson.E{Key: field, Value: order}})
295
+ }
286
296
  cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
287
297
  if err == nil {
288
298
  cursor.All(ctx, &results)
@@ -300,6 +310,15 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
300
310
  if ok {
301
311
  var results []models.{{capitalize name}}
302
312
  opts := options.Find().SetSkip(int64((req.Page - 1) * req.PageSize)).SetLimit(int64(req.PageSize))
313
+ if req.Sort != "" {
314
+ parts := strings.Split(req.Sort, ",")
315
+ field := parts[0]
316
+ order := 1
317
+ if len(parts) > 1 && strings.ToLower(parts[1]) == "desc" {
318
+ order = -1
319
+ }
320
+ opts.SetSort(bson.D{bson.E{Key: field, Value: order}})
321
+ }
303
322
  cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
304
323
  if err == nil {
305
324
  cursor.All(ctx, &results)
@@ -319,7 +338,9 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
319
338
  for role, db := range siloConns {
320
339
  var results []models.{{capitalize name}}
321
340
  query := db.WithContext(ctx).Model(&models.{{capitalize name}}{})
322
-
341
+ if req.Sort != "" {
342
+ query = query.Order(strings.ReplaceAll(req.Sort, ",", " "))
343
+ }
323
344
  var count int64
324
345
  query.Count(&count)
325
346
  total += count
@@ -338,7 +359,9 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
338
359
  if ok {
339
360
  var results []models.{{capitalize name}}
340
361
  query := db.WithContext(ctx).Model(&models.{{capitalize name}}{})
341
-
362
+ if req.Sort != "" {
363
+ query = query.Order(strings.ReplaceAll(req.Sort, ",", " "))
364
+ }
342
365
  var count int64
343
366
  query.Count(&count)
344
367
  total = count
@@ -83,6 +83,7 @@ message List{{capitalize name}}Request {
83
83
  int32 page = 1;
84
84
  int32 page_size = 2;
85
85
  string query = 3;
86
+ string sort = 4;
86
87
  }
87
88
 
88
89
  message List{{capitalize name}}Reply {