go-duck-cli 1.1.36 → 1.1.40

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.
@@ -147,6 +147,8 @@ export const generateKratosCode = async (entities, projectRootDir, projectName,
147
147
  annotation: entity.annotation,
148
148
  isDocument: entity.isDocument || false,
149
149
  isAudited: entity.isAudited || false,
150
+ isFederated: entity.isFederated || false,
151
+ needFmt: (entity.isDocument || false) || !(entity.isFederated || false),
150
152
  projectName,
151
153
  enums
152
154
  };
@@ -278,7 +280,8 @@ import (
278
280
 
279
281
  func TenantServerInterceptor(conf *config.Config, db *gorm.DB) middleware.Middleware {
280
282
  mgr := my_middleware.GetTenantManager(db, conf)
281
- fallbackDB := strings.ToLower(conf.GoDuck.Name) + "_fallback"
283
+ fallbackDB := conf.GoDuck.Datasource.Database
284
+ fallbackMongoDB := conf.GoDuck.Datasource.MongoDB.Database
282
285
 
283
286
  return func(handler middleware.Handler) middleware.Handler {
284
287
  return func(ctx context.Context, req interface{}) (interface{}, error) {
@@ -316,7 +319,11 @@ func TenantServerInterceptor(conf *config.Config, db *gorm.DB) middleware.Middle
316
319
  db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ? AND tenant_id = ?", lowerRoles, requestedTenant).Scan(&mappings)
317
320
  }
318
321
  } else {
319
- db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ?", lowerRoles).Scan(&mappings)
322
+ if isAdmin {
323
+ db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles").Scan(&mappings)
324
+ } else {
325
+ db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ?", lowerRoles).Scan(&mappings)
326
+ }
320
327
  }
321
328
 
322
329
  siloConnections := make(map[string]*gorm.DB)
@@ -338,9 +345,9 @@ func TenantServerInterceptor(conf *config.Config, db *gorm.DB) middleware.Middle
338
345
  ctx = context.WithValue(ctx, "tenantDBConn", conn)
339
346
 
340
347
  if conf.GoDuck.Datasource.MongoDB.Enabled {
341
- mClient, err := mgr.GetMongoClient(fallbackDB)
348
+ mClient, err := mgr.GetMongoClient(fallbackMongoDB)
342
349
  if err == nil && mClient != nil {
343
- mDB := mClient.Database(fallbackDB)
350
+ mDB := mClient.Database(fallbackMongoDB)
344
351
  mongoConnections["fallback"] = mDB
345
352
  ctx = context.WithValue(ctx, "tenantMongoDB", mDB)
346
353
  }
@@ -129,7 +129,8 @@ func (m *TenantDBManager) GetMongoClient(dbName string) (*mongo.Client, error) {
129
129
 
130
130
  func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
131
131
  mgr := GetTenantManager(db, cfg)
132
- fallbackDB := strings.ToLower(cfg.GoDuck.Name) + "_fallback"
132
+ fallbackDB := cfg.GoDuck.Datasource.Database
133
+ fallbackMongoDB := cfg.GoDuck.Datasource.MongoDB.Database
133
134
 
134
135
  return func(c *gin.Context) {
135
136
  userRolesInterface, exists := c.Get("UserRoles")
@@ -179,7 +180,11 @@ func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
179
180
  db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ? AND tenant_id IN ?", lowerRoles, requestedTenants).Scan(&mappings)
180
181
  }
181
182
  } else {
182
- db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ?", lowerRoles).Scan(&mappings)
183
+ if isAdmin {
184
+ db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles").Scan(&mappings)
185
+ } else {
186
+ db.Raw("SELECT role_name, db_name, is_primary FROM tenant_roles WHERE LOWER(role_name) IN ?", lowerRoles).Scan(&mappings)
187
+ }
183
188
  }
184
189
 
185
190
  // Filter out unauthorized mappings (e.g. admin_db for non-admins)
@@ -203,13 +208,13 @@ func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
203
208
  c.Set("tenantDBConn", conn)
204
209
 
205
210
  if cfg.GoDuck.Datasource.MongoDB.Enabled {
206
- mClient, err := mgr.GetMongoClient(fallbackDB)
211
+ mClient, err := mgr.GetMongoClient(fallbackMongoDB)
207
212
  if err != nil || mClient == nil {
208
213
  c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to resolve tenant fallback MongoDB connection"})
209
214
  c.Abort()
210
215
  return
211
216
  }
212
- mDB := mClient.Database(fallbackDB)
217
+ mDB := mClient.Database(fallbackMongoDB)
213
218
  mongoConnections["fallback"] = mDB
214
219
  c.Set("tenantMongoDB", mDB)
215
220
  }
@@ -281,7 +286,8 @@ func TenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
281
286
 
282
287
  func PublicTenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
283
288
  mgr := GetTenantManager(db, cfg)
284
- fallbackDB := strings.ToLower(cfg.GoDuck.Name) + "_fallback"
289
+ fallbackDB := cfg.GoDuck.Datasource.Database
290
+ fallbackMongoDB := cfg.GoDuck.Datasource.MongoDB.Database
285
291
 
286
292
  return func(c *gin.Context) {
287
293
  requestedTenantRaw := strings.ToLower(c.GetHeader("X-Tenant-ID"))
@@ -299,11 +305,15 @@ func PublicTenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
299
305
  var mappings []models.TenantRole
300
306
  if len(requestedTenants) > 0 {
301
307
  db.Raw("SELECT db_name, is_primary FROM tenant_roles WHERE tenant_id IN ?", requestedTenants).Scan(&mappings)
308
+ } else {
309
+ db.Raw("SELECT db_name, is_primary FROM tenant_roles ORDER BY is_primary DESC, id ASC LIMIT 1").Scan(&mappings)
302
310
  }
303
311
 
304
312
  dbName := fallbackDB
313
+ mongoDbName := fallbackMongoDB
305
314
  if len(mappings) > 0 {
306
315
  dbName = mappings[0].DBName
316
+ mongoDbName = mappings[0].DBName
307
317
  }
308
318
 
309
319
  tenantConn, err := mgr.GetDB(dbName)
@@ -316,9 +326,9 @@ func PublicTenantMiddleware(db *gorm.DB, cfg *config.Config) gin.HandlerFunc {
316
326
  c.Set("tenantDBConn", tenantConn)
317
327
 
318
328
  if cfg.GoDuck.Datasource.MongoDB.Enabled {
319
- mClient, err := mgr.GetMongoClient(dbName)
329
+ mClient, err := mgr.GetMongoClient(mongoDbName)
320
330
  if err == nil && mClient != nil {
321
- c.Set("tenantMongoDB", mClient.Database(dbName))
331
+ c.Set("tenantMongoDB", mClient.Database(mongoDbName))
322
332
  }
323
333
  }
324
334
 
package/index.js CHANGED
@@ -642,6 +642,47 @@ program
642
642
  if (await fs.pathExists(p)) await fs.remove(p);
643
643
  }
644
644
 
645
+ const goModPath = path.join(absoluteOutputDir, 'go.mod');
646
+ if (!await fs.pathExists(goModPath)) {
647
+ const goModContent = `module ${config.name}
648
+
649
+ go 1.24
650
+
651
+ require (
652
+ github.com/gin-gonic/gin v1.10.0
653
+ github.com/go-kratos/kratos/v2 v2.8.2
654
+ github.com/google/uuid v1.6.0
655
+ github.com/spf13/viper v1.19.0
656
+ go.opentelemetry.io/otel v1.26.0
657
+ go.opentelemetry.io/otel/trace v1.26.0
658
+ go.opentelemetry.io/otel/sdk v1.26.0
659
+ go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.51.0
660
+ google.golang.org/grpc v1.64.0
661
+ gorm.io/datatypes v1.2.0
662
+ gorm.io/driver/postgres v1.5.7
663
+ gorm.io/gorm v1.25.10
664
+ gorm.io/plugin/opentelemetry v0.1.5
665
+ github.com/golang-jwt/jwt/v5 v5.2.1
666
+ github.com/eclipse/paho.mqtt.golang v1.4.3
667
+ github.com/sony/gobreaker v0.5.0
668
+ github.com/redis/go-redis/v9 v9.5.1
669
+ github.com/gorilla/websocket v1.5.1
670
+ github.com/99designs/gqlgen v0.17.44
671
+ github.com/vektah/gqlparser/v2 v2.5.11
672
+ github.com/aws/aws-lambda-go v1.47.0
673
+ github.com/awslabs/aws-lambda-go-api-proxy v0.16.1
674
+ github.com/GoogleCloudPlatform/functions-framework-go v1.8.1
675
+ go.mongodb.org/mongo-driver v1.17.1
676
+ github.com/gin-contrib/cors v1.7.1
677
+ github.com/go-resty/resty/v2 v2.16.0
678
+ github.com/olivere/elastic/v7 v7.0.32
679
+ github.com/nats-io/nats.go v1.38.0
680
+ )
681
+ `;
682
+ await fs.writeFile(goModPath, goModContent);
683
+ console.log(chalk.green('✅ go.mod file created!'));
684
+ }
685
+
645
686
  await generateConfigLoader(absoluteOutputDir);
646
687
  await generateLoggerCode(config, absoluteOutputDir);
647
688
  await generateMQTTCode(config, absoluteOutputDir);
@@ -657,6 +698,13 @@ program
657
698
  await generateGraphQLCode(config, entities, relationships, absoluteOutputDir, enums);
658
699
  await generatePostgRESTCode(config, absoluteOutputDir);
659
700
 
701
+ if (config.multitenancy?.enabled) await generateMultitenancy(config, absoluteOutputDir, entities);
702
+ await generateAuditCode(config, absoluteOutputDir);
703
+ await generateMeteringCode(config, absoluteOutputDir);
704
+ await generateOutbox(absoluteOutputDir, config);
705
+ await generateNATSCode(config, absoluteOutputDir);
706
+ await generateBrokerCode(config, absoluteOutputDir);
707
+
660
708
  // Sync Search & Security
661
709
  await generateElasticsearchLayer(config, entities, absoluteOutputDir);
662
710
  await generateSecurityMiddleware(config, absoluteOutputDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "go-duck-cli",
3
- "version": "1.1.36",
3
+ "version": "1.1.40",
4
4
  "description": "The Ultimate Evolutionary Go Microservice Scaffolder.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -147,6 +147,11 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
147
147
  page, _ := strconv.Atoi(c.DefaultQuery("page", "0"))
148
148
  size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
149
149
 
150
+ offset := 0
151
+ if page > 0 {
152
+ offset = (page - 1) * size
153
+ }
154
+
150
155
  {{#if isDocument}}
151
156
  // 🦆 MongoDB Path
152
157
  {{#if isFederated}}
@@ -163,7 +168,7 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
163
168
  go func(r string, db *mongo.Database) {
164
169
  defer wg.Done()
165
170
  var entities []models.{{capitalize name}}
166
- opts := options.Find().SetSkip(int64(page * size)).SetLimit(int64(size))
171
+ opts := options.Find().SetSkip(int64(offset)).SetLimit(int64(size))
167
172
  cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
168
173
  if err == nil {
169
174
  cursor.All(ctx, &entities)
@@ -194,7 +199,7 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
194
199
  c.Header("X-Total-Count", strconv.FormatInt(totalCount, 10))
195
200
 
196
201
  var entities []models.{{capitalize name}}
197
- opts := options.Find().SetSkip(int64(page * size)).SetLimit(int64(size))
202
+ opts := options.Find().SetSkip(int64(offset)).SetLimit(int64(size))
198
203
  cursor, err := tenantDB.Collection("{{toLowerCase name}}s").Find(ctx, filter, opts)
199
204
  if err != nil {
200
205
  c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
@@ -222,7 +227,7 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
222
227
  go func(r string, db *gorm.DB) {
223
228
  defer wg.Done()
224
229
  var entities []models.{{capitalize name}}
225
- if err := db.WithContext(ctx).Offset(page * size).Limit(size).Find(&entities).Error; err == nil {
230
+ if err := db.WithContext(ctx).Offset(offset).Limit(size).Find(&entities).Error; err == nil {
226
231
  mu.Lock()
227
232
  federatedData[r] = entities
228
233
  mu.Unlock()
@@ -243,7 +248,7 @@ func (ctrl *{{capitalize name}}Controller) GetAll(c *gin.Context) {
243
248
  c.Header("X-Total-Count", strconv.FormatInt(totalCount, 10))
244
249
 
245
250
  var entities []models.{{capitalize name}}
246
- if err := tenantDB.WithContext(ctx).Offset(page * size).Limit(size).Find(&entities).Error; err != nil {
251
+ if err := tenantDB.WithContext(ctx).Offset(offset).Limit(size).Find(&entities).Error; err != nil {
247
252
  c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
248
253
  return
249
254
  }
@@ -5,7 +5,6 @@ import (
5
5
  "fmt"
6
6
  "log"
7
7
  "net/http"
8
- "strings"
9
8
  "time"
10
9
 
11
10
  "github.com/gin-gonic/gin"
@@ -87,29 +86,32 @@ func SetupRouter(appConfig *config.Config) *gin.Engine {
87
86
  logger.Error("Goose Migration failed: %v", err)
88
87
  }
89
88
 
90
- // 10b. Initialize and Migrate Fallback DB if multi-tenancy is enabled
89
+ // 10b. Initialize and Migrate Fallback DB if multi-tenancy is enabled and different from master DB
91
90
  if appConfig.GoDuck.Multitenancy.Enabled {
92
- fallbackDB := strings.ToLower(appConfig.GoDuck.Name) + "_fallback"
93
- var exists int
94
- masterDB.Raw("SELECT 1 FROM pg_database WHERE datname = ?", fallbackDB).Scan(&exists)
95
- if exists == 0 {
96
- if err := masterDB.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", fallbackDB)).Error; err != nil {
97
- log.Printf("Warning: Failed to create fallback database %s: %v", fallbackDB, err)
98
- } else {
99
- log.Printf(" Created fallback database: %s", fallbackDB)
91
+ fallbackDB := appConfig.GoDuck.Datasource.Database
92
+ masterDBName := appConfig.GoDuck.Datasource.Database
93
+ if fallbackDB != masterDBName {
94
+ var exists int
95
+ masterDB.Raw("SELECT 1 FROM pg_database WHERE datname = ?", fallbackDB).Scan(&exists)
96
+ if exists == 0 {
97
+ if err := masterDB.Exec(fmt.Sprintf("CREATE DATABASE \"%s\"", fallbackDB)).Error; err != nil {
98
+ log.Printf("Warning: Failed to create fallback database %s: %v", fallbackDB, err)
99
+ } else {
100
+ log.Printf("✅ Created fallback database: %s", fallbackDB)
101
+ }
100
102
  }
101
- }
102
103
 
103
- // Run tenant migrations on the fallback database
104
- mgr := middleware.GetTenantManager(masterDB, appConfig)
105
- if fDB, err := mgr.GetDB(fallbackDB); err == nil {
106
- if err := migrations.RunGoNativeMigrationsForTenant(fDB); err != nil {
107
- log.Printf("Warning: Failed to run migrations on fallback database: %v", err)
104
+ // Run tenant migrations on the fallback database
105
+ mgr := middleware.GetTenantManager(masterDB, appConfig)
106
+ if fDB, err := mgr.GetDB(fallbackDB); err == nil {
107
+ if err := migrations.RunGoNativeMigrationsForTenant(fDB); err != nil {
108
+ log.Printf("Warning: Failed to run migrations on fallback database: %v", err)
109
+ } else {
110
+ log.Printf("✅ Migrated fallback database: %s", fallbackDB)
111
+ }
108
112
  } else {
109
- log.Printf(" Migrated fallback database: %s", fallbackDB)
113
+ log.Printf("Warning: Failed to connect to fallback database for migration: %v", err)
110
114
  }
111
- } else {
112
- log.Printf("Warning: Failed to connect to fallback database for migration: %v", err)
113
115
  }
114
116
  }
115
117
  }
@@ -2,7 +2,7 @@ package service
2
2
 
3
3
  import (
4
4
  "context"
5
- {{#if isDocument}}
5
+ {{#if needFmt}}
6
6
  "fmt"
7
7
  {{/if}}
8
8
  {{#if (hasNested fields)}}
@@ -38,10 +38,19 @@ func New{{capitalize name}}Service(repo *repository.Repository) *{{capitalize na
38
38
 
39
39
  func (s *{{capitalize name}}Service) Create{{capitalize name}}(ctx context.Context, req *pb.Create{{capitalize name}}Request) (*pb.{{capitalize name}}Reply, error) {
40
40
  {{#if isDocument}}
41
+ {{#if isFederated}}
42
+ siloConns, _ := ctx.Value("tenantMongoConnections").(map[string]*mongo.Database)
43
+ {{else}}
41
44
  db, ok := ctx.Value("tenantMongoDB").(*mongo.Database)
42
45
  if !ok { return nil, fmt.Errorf("mongo database not found in context") }
46
+ {{/if}}
43
47
  {{else}}
48
+ {{#if isFederated}}
44
49
  siloConns, _ := ctx.Value("tenantSiloConns").(map[string]*gorm.DB)
50
+ {{else}}
51
+ db, ok := ctx.Value("tenantDBConn").(*gorm.DB)
52
+ if !ok { return nil, fmt.Errorf("database not found in context") }
53
+ {{/if}}
45
54
  {{/if}}
46
55
  federatedData := make(map[string]*pb.{{capitalize name}})
47
56
 
@@ -67,17 +76,33 @@ func (s *{{capitalize name}}Service) Create{{capitalize name}}(ctx context.Conte
67
76
  {{#each fields}}{{#if isNested}}
68
77
  json.Unmarshal([]byte(req.{{toProtoFieldName name}}), &entity.{{capitalize name}})
69
78
  {{/if}}{{/each}}
79
+ {{#if isFederated}}
80
+ for role, dbCon := range siloConns {
81
+ res, err := dbCon.Collection("{{toLowerCase name}}s").InsertOne(ctx, entity)
82
+ if err == nil {
83
+ entity.ID = fmt.Sprintf("%v", res.InsertedID)
84
+ federatedData[role] = map{{capitalize name}}ToPb(entity)
85
+ }
86
+ }
87
+ {{else}}
70
88
  res, err := db.Collection("{{toLowerCase name}}s").InsertOne(ctx, entity)
71
89
  if err == nil {
72
90
  entity.ID = fmt.Sprintf("%v", res.InsertedID)
73
91
  federatedData["tenant"] = map{{capitalize name}}ToPb(entity)
74
92
  }
93
+ {{/if}}
75
94
  {{else}}
76
- for role, db := range siloConns {
77
- if err := db.WithContext(ctx).Create(entity).Error; err == nil {
95
+ {{#if isFederated}}
96
+ for role, dbCon := range siloConns {
97
+ if err := dbCon.WithContext(ctx).Create(entity).Error; err == nil {
78
98
  federatedData[role] = map{{capitalize name}}ToPb(entity)
79
99
  }
80
100
  }
101
+ {{else}}
102
+ if err := db.WithContext(ctx).Create(entity).Error; err == nil {
103
+ federatedData["tenant"] = map{{capitalize name}}ToPb(entity)
104
+ }
105
+ {{/if}}
81
106
  {{/if}}
82
107
 
83
108
  return &pb.{{capitalize name}}Reply{
@@ -89,12 +114,25 @@ func (s *{{capitalize name}}Service) Get{{capitalize name}}(ctx context.Context,
89
114
  federatedData := make(map[string]*pb.{{capitalize name}})
90
115
 
91
116
  {{#if isDocument}}
92
- db, _ := ctx.Value("tenantMongoDB").(*mongo.Database)
93
- var entity models.{{capitalize name}}
94
- if err := db.Collection("{{toLowerCase name}}s").FindOne(ctx, bson.M{"_id": req.Id}).Decode(&entity); err == nil {
95
- federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
117
+ {{#if isFederated}}
118
+ siloConns, _ := ctx.Value("tenantMongoConnections").(map[string]*mongo.Database)
119
+ for role, db := range siloConns {
120
+ var entity models.{{capitalize name}}
121
+ if err := db.Collection("{{toLowerCase name}}s").FindOne(ctx, bson.M{"_id": req.Id}).Decode(&entity); err == nil {
122
+ federatedData[role] = map{{capitalize name}}ToPb(&entity)
123
+ }
124
+ }
125
+ {{else}}
126
+ db, ok := ctx.Value("tenantMongoDB").(*mongo.Database)
127
+ if ok {
128
+ var entity models.{{capitalize name}}
129
+ if err := db.Collection("{{toLowerCase name}}s").FindOne(ctx, bson.M{"_id": req.Id}).Decode(&entity); err == nil {
130
+ federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
131
+ }
96
132
  }
133
+ {{/if}}
97
134
  {{else}}
135
+ {{#if isFederated}}
98
136
  siloConns, _ := ctx.Value("tenantSiloConns").(map[string]*gorm.DB)
99
137
  for role, db := range siloConns {
100
138
  var entity models.{{capitalize name}}
@@ -102,6 +140,15 @@ func (s *{{capitalize name}}Service) Get{{capitalize name}}(ctx context.Context,
102
140
  federatedData[role] = map{{capitalize name}}ToPb(&entity)
103
141
  }
104
142
  }
143
+ {{else}}
144
+ db, ok := ctx.Value("tenantDBConn").(*gorm.DB)
145
+ if ok {
146
+ var entity models.{{capitalize name}}
147
+ if err := db.WithContext(ctx).First(&entity, req.Id).Error; err == nil {
148
+ federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
149
+ }
150
+ }
151
+ {{/if}}
105
152
  {{/if}}
106
153
 
107
154
  return &pb.{{capitalize name}}Reply{
@@ -133,17 +180,37 @@ func (s *{{capitalize name}}Service) Update{{capitalize name}}(ctx context.Conte
133
180
  {{/each}}
134
181
 
135
182
  {{#if isDocument}}
136
- db, _ := ctx.Value("tenantMongoDB").(*mongo.Database)
137
- if _, err := db.Collection("{{toLowerCase name}}s").ReplaceOne(ctx, bson.M{"_id": req.Id}, entity); err == nil {
138
- federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
183
+ {{#if isFederated}}
184
+ siloConns, _ := ctx.Value("tenantMongoConnections").(map[string]*mongo.Database)
185
+ for role, db := range siloConns {
186
+ if _, err := db.Collection("{{toLowerCase name}}s").ReplaceOne(ctx, bson.M{"_id": req.Id}, entity); err == nil {
187
+ federatedData[role] = map{{capitalize name}}ToPb(&entity)
188
+ }
139
189
  }
140
190
  {{else}}
191
+ db, ok := ctx.Value("tenantMongoDB").(*mongo.Database)
192
+ if ok {
193
+ if _, err := db.Collection("{{toLowerCase name}}s").ReplaceOne(ctx, bson.M{"_id": req.Id}, entity); err == nil {
194
+ federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
195
+ }
196
+ }
197
+ {{/if}}
198
+ {{else}}
199
+ {{#if isFederated}}
141
200
  siloConns, _ := ctx.Value("tenantSiloConns").(map[string]*gorm.DB)
142
201
  for role, db := range siloConns {
143
202
  if err := db.WithContext(ctx).Model(&models.{{capitalize name}}{}).Where("id = ?", req.Id).Save(&entity).Error; err == nil {
144
203
  federatedData[role] = map{{capitalize name}}ToPb(&entity)
145
204
  }
146
205
  }
206
+ {{else}}
207
+ db, ok := ctx.Value("tenantDBConn").(*gorm.DB)
208
+ if ok {
209
+ if err := db.WithContext(ctx).Model(&models.{{capitalize name}}{}).Where("id = ?", req.Id).Save(&entity).Error; err == nil {
210
+ federatedData["tenant"] = map{{capitalize name}}ToPb(&entity)
211
+ }
212
+ }
213
+ {{/if}}
147
214
  {{/if}}
148
215
 
149
216
  return &pb.{{capitalize name}}Reply{
@@ -153,13 +220,29 @@ func (s *{{capitalize name}}Service) Update{{capitalize name}}(ctx context.Conte
153
220
 
154
221
  func (s *{{capitalize name}}Service) Delete{{capitalize name}}(ctx context.Context, req *pb.Delete{{capitalize name}}Request) (*pb.Delete{{capitalize name}}Reply, error) {
155
222
  {{#if isDocument}}
156
- db, _ := ctx.Value("tenantMongoDB").(*mongo.Database)
157
- db.Collection("{{toLowerCase name}}s").DeleteOne(ctx, bson.M{"_id": req.Id})
223
+ {{#if isFederated}}
224
+ siloConns, _ := ctx.Value("tenantMongoConnections").(map[string]*mongo.Database)
225
+ for _, db := range siloConns {
226
+ db.Collection("{{toLowerCase name}}s").DeleteOne(ctx, bson.M{"_id": req.Id})
227
+ }
228
+ {{else}}
229
+ db, ok := ctx.Value("tenantMongoDB").(*mongo.Database)
230
+ if ok {
231
+ db.Collection("{{toLowerCase name}}s").DeleteOne(ctx, bson.M{"_id": req.Id})
232
+ }
233
+ {{/if}}
158
234
  {{else}}
235
+ {{#if isFederated}}
159
236
  siloConns, _ := ctx.Value("tenantSiloConns").(map[string]*gorm.DB)
160
237
  for _, db := range siloConns {
161
238
  db.WithContext(ctx).Where("id = ?", req.Id).Delete(&models.{{capitalize name}}{})
162
239
  }
240
+ {{else}}
241
+ db, ok := ctx.Value("tenantDBConn").(*gorm.DB)
242
+ if ok {
243
+ db.WithContext(ctx).Where("id = ?", req.Id).Delete(&models.{{capitalize name}}{})
244
+ }
245
+ {{/if}}
163
246
  {{/if}}
164
247
  return &pb.Delete{{capitalize name}}Reply{Message: "Delete completed"}, nil
165
248
  }
@@ -169,21 +252,43 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
169
252
  var total int64
170
253
 
171
254
  {{#if isDocument}}
172
- db, _ := ctx.Value("tenantMongoDB").(*mongo.Database)
173
- var results []models.{{capitalize name}}
174
- opts := options.Find().SetSkip(int64((req.Page - 1) * req.PageSize)).SetLimit(int64(req.PageSize))
175
- cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
176
- if err == nil {
177
- cursor.All(ctx, &results)
178
- items := make([]*pb.{{capitalize name}}, len(results))
179
- for i, r := range results {
180
- items[i] = map{{capitalize name}}ToPb(&r)
255
+ {{#if isFederated}}
256
+ siloConns, _ := ctx.Value("tenantMongoConnections").(map[string]*mongo.Database)
257
+ for role, db := range siloConns {
258
+ var results []models.{{capitalize name}}
259
+ opts := options.Find().SetSkip(int64((req.Page - 1) * req.PageSize)).SetLimit(int64(req.PageSize))
260
+ cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
261
+ if err == nil {
262
+ cursor.All(ctx, &results)
263
+ items := make([]*pb.{{capitalize name}}, len(results))
264
+ for i, r := range results {
265
+ items[i] = map{{capitalize name}}ToPb(&r)
266
+ }
267
+ federatedResults[role] = &pb.{{capitalize name}}List{Items: items}
268
+ count, _ := db.Collection("{{toLowerCase name}}s").CountDocuments(ctx, bson.M{})
269
+ total += count
181
270
  }
182
- federatedResults["tenant"] = &pb.{{capitalize name}}List{Items: items}
183
- count, _ := db.Collection("{{toLowerCase name}}s").CountDocuments(ctx, bson.M{})
184
- total = count
185
271
  }
186
272
  {{else}}
273
+ db, ok := ctx.Value("tenantMongoDB").(*mongo.Database)
274
+ if ok {
275
+ var results []models.{{capitalize name}}
276
+ opts := options.Find().SetSkip(int64((req.Page - 1) * req.PageSize)).SetLimit(int64(req.PageSize))
277
+ cursor, err := db.Collection("{{toLowerCase name}}s").Find(ctx, bson.M{}, opts)
278
+ if err == nil {
279
+ cursor.All(ctx, &results)
280
+ items := make([]*pb.{{capitalize name}}, len(results))
281
+ for i, r := range results {
282
+ items[i] = map{{capitalize name}}ToPb(&r)
283
+ }
284
+ federatedResults["tenant"] = &pb.{{capitalize name}}List{Items: items}
285
+ count, _ := db.Collection("{{toLowerCase name}}s").CountDocuments(ctx, bson.M{})
286
+ total = count
287
+ }
288
+ }
289
+ {{/if}}
290
+ {{else}}
291
+ {{#if isFederated}}
187
292
  siloConns, _ := ctx.Value("tenantSiloConns").(map[string]*gorm.DB)
188
293
  for role, db := range siloConns {
189
294
  var results []models.{{capitalize name}}
@@ -202,6 +307,26 @@ func (s *{{capitalize name}}Service) List{{capitalize name}}(ctx context.Context
202
307
  federatedResults[role] = &pb.{{capitalize name}}List{Items: items}
203
308
  }
204
309
  }
310
+ {{else}}
311
+ db, ok := ctx.Value("tenantDBConn").(*gorm.DB)
312
+ if ok {
313
+ var results []models.{{capitalize name}}
314
+ query := db.WithContext(ctx).Model(&models.{{capitalize name}}{})
315
+
316
+ var count int64
317
+ query.Count(&count)
318
+ total = count
319
+
320
+ offset := (req.Page - 1) * req.PageSize
321
+ if err := query.Limit(int(req.PageSize)).Offset(int(offset)).Find(&results).Error; err == nil {
322
+ items := make([]*pb.{{capitalize name}}, len(results))
323
+ for i, r := range results {
324
+ items[i] = map{{capitalize name}}ToPb(&r)
325
+ }
326
+ federatedResults["tenant"] = &pb.{{capitalize name}}List{Items: items}
327
+ }
328
+ }
329
+ {{/if}}
205
330
  {{/if}}
206
331
 
207
332
  return &pb.List{{capitalize name}}Reply{