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.
- package/generators/kratos.js +11 -4
- package/generators/multitenancy.js +17 -7
- package/index.js +48 -0
- package/package.json +1 -1
- package/templates/go/controller.go.hbs +9 -4
- package/templates/go/router.go.hbs +21 -19
- package/templates/kratos/service.go.hbs +149 -24
package/generators/kratos.js
CHANGED
|
@@ -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 :=
|
|
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
|
-
|
|
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(
|
|
348
|
+
mClient, err := mgr.GetMongoClient(fallbackMongoDB)
|
|
342
349
|
if err == nil && mClient != nil {
|
|
343
|
-
mDB := mClient.Database(
|
|
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 :=
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 :=
|
|
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(
|
|
329
|
+
mClient, err := mgr.GetMongoClient(mongoDbName)
|
|
320
330
|
if err == nil && mClient != nil {
|
|
321
|
-
c.Set("tenantMongoDB", mClient.Database(
|
|
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
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 :=
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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("
|
|
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
|
|
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
|
-
|
|
77
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
cursor.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
items[
|
|
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{
|