go-duck-cli 1.4.6 → 1.4.10
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/postman.js +5 -3
- package/generators/swagger.js +4 -2
- package/generators/telemetry.js +136 -9
- package/go.mod +15 -0
- package/go.sum +20 -0
- package/index.js +13 -4
- package/package.json +1 -1
- package/parser/gdl.js +9 -5
- package/templates/docs/pages/gdl-entities.hbs +53 -0
- package/templates/go/entity.go.hbs +3 -0
- package/templates/go/router.go.hbs +196 -13
- package/test-go/devops/k8s/otel-collector.yml +23 -0
- package/test-go/go.mod +64 -0
- package/test-go/go.sum +154 -0
- package/test-go/internal/telemetry/metrics_collector.go +88 -0
- package/test-go/internal/telemetry/otel.go +69 -0
- package/test-go/internal/telemetry/system_metrics.go +198 -0
- package/test_datatypes.go +19 -0
- package/test_time.go +22 -0
package/generators/postman.js
CHANGED
|
@@ -178,7 +178,8 @@ export const generatePostmanCollection = async (config, entities, outputDir, ope
|
|
|
178
178
|
if (f.type === 'Integer' || f.type === 'Long') return `${f.name}: 100`;
|
|
179
179
|
if (f.type === 'Float' || f.type === 'BigDecimal') return `${f.name}: 99.99`;
|
|
180
180
|
if (f.type === 'Boolean') return `${f.name}: true`;
|
|
181
|
-
if (f.type === '
|
|
181
|
+
if (f.type === 'Time') return `${f.name}: "0000-01-01T12:00:00Z"`;
|
|
182
|
+
if (f.type === 'LocalDate') return `${f.name}: "2024-01-01T00:00:00Z"`;
|
|
182
183
|
if (f.type === 'Instant') return `${f.name}: "2024-01-01T12:00:00Z"`;
|
|
183
184
|
if (f.type === 'JSON' || f.type === 'JSONB') return `${f.name}: "{\\"attribute\\": \\"example_value\\"}"`;
|
|
184
185
|
return `${f.name}: "test"`;
|
|
@@ -361,9 +362,10 @@ export const generatePostmanCollection = async (config, entities, outputDir, ope
|
|
|
361
362
|
for (const f of fields) {
|
|
362
363
|
if (f.type === 'String' || f.type === 'Text') obj[f.name] = "Sample " + f.name;
|
|
363
364
|
else if (f.type === 'Integer' || f.type === 'Long') obj[f.name] = 100;
|
|
364
|
-
else if (f.type === 'Float' || f.type === 'BigDecimal') obj[f.name] = 99.99;
|
|
365
|
+
else if (f.type === 'Float' || f.type === 'Double' || f.type === 'BigDecimal') obj[f.name] = 99.99;
|
|
365
366
|
else if (f.type === 'Boolean') obj[f.name] = true;
|
|
366
|
-
else if (f.type === '
|
|
367
|
+
else if (f.type === 'Time') obj[f.name] = "0000-01-01T12:00:00Z";
|
|
368
|
+
else if (f.type === 'LocalDate') obj[f.name] = "2024-01-01T00:00:00Z";
|
|
367
369
|
else if (f.type === 'Instant' || f.type === 'DateTime' || f.type === 'Datetime') obj[f.name] = "2024-01-01T12:00:00Z";
|
|
368
370
|
else if (f.type === 'JSON' || f.type === 'JSONB') obj[f.name] = {"attribute": "example_value"};
|
|
369
371
|
else if (f.isEnum) obj[f.name] = "ACTIVE"; // Safe fallback for enums
|
package/generators/swagger.js
CHANGED
|
@@ -322,11 +322,13 @@ const getSwaggerFieldSchema = (type) => {
|
|
|
322
322
|
const schemas = {
|
|
323
323
|
'String': { type: 'string' },
|
|
324
324
|
'Integer': { type: 'integer', format: 'int32' },
|
|
325
|
-
'Float': { type: 'number', format: '
|
|
325
|
+
'Float': { type: 'number', format: 'float' },
|
|
326
|
+
'Double': { type: 'number', format: 'double' },
|
|
326
327
|
'Boolean': { type: 'boolean' },
|
|
328
|
+
'Time': { type: 'string', format: 'date-time' },
|
|
327
329
|
'Long': { type: 'integer', format: 'int64' },
|
|
328
330
|
'BigDecimal': { type: 'number', format: 'double' },
|
|
329
|
-
'LocalDate': { type: 'string', format: 'date' },
|
|
331
|
+
'LocalDate': { type: 'string', format: 'date-time' },
|
|
330
332
|
'Instant': { type: 'string', format: 'date-time' },
|
|
331
333
|
'JSON': { type: 'object' },
|
|
332
334
|
'JSONB': { type: 'object' },
|
package/generators/telemetry.js
CHANGED
|
@@ -130,7 +130,7 @@ type StatusStats struct {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
type AppMetrics struct {
|
|
133
|
-
|
|
133
|
+
Mu sync.RWMutex
|
|
134
134
|
StartTime time.Time
|
|
135
135
|
Endpoints map[string]*EndpointStats
|
|
136
136
|
StatusCodes map[int]*StatusStats
|
|
@@ -157,8 +157,8 @@ func MetricsTrackingMiddleware(cfg *config.Config) gin.HandlerFunc {
|
|
|
157
157
|
}
|
|
158
158
|
endpointKey := method + " " + path
|
|
159
159
|
|
|
160
|
-
globalMetrics.
|
|
161
|
-
defer globalMetrics.
|
|
160
|
+
globalMetrics.Mu.Lock()
|
|
161
|
+
defer globalMetrics.Mu.Unlock()
|
|
162
162
|
|
|
163
163
|
// Status Code tracking
|
|
164
164
|
if _, exists := globalMetrics.StatusCodes[status]; !exists {
|
|
@@ -203,8 +203,18 @@ import (
|
|
|
203
203
|
"time"
|
|
204
204
|
"github.com/shirou/gopsutil/v3/cpu"
|
|
205
205
|
"github.com/shirou/gopsutil/v3/process"
|
|
206
|
+
"github.com/shirou/gopsutil/v3/mem"
|
|
206
207
|
"os"
|
|
207
208
|
"fmt"
|
|
209
|
+
"strconv"
|
|
210
|
+
"strings"
|
|
211
|
+
"sync"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
var (
|
|
215
|
+
cgroupCPULock sync.Mutex
|
|
216
|
+
lastCgroupTime time.Time
|
|
217
|
+
lastCgroupUsageNs uint64
|
|
208
218
|
)
|
|
209
219
|
|
|
210
220
|
type SystemMetrics struct {
|
|
@@ -212,9 +222,13 @@ type SystemMetrics struct {
|
|
|
212
222
|
StartTime string \`json:"start_time"\`
|
|
213
223
|
ProcessCPUUsage float64 \`json:"process_cpu_usage"\`
|
|
214
224
|
SystemCPUUsage float64 \`json:"system_cpu_usage"\`
|
|
225
|
+
PodCPULimitPct float64 \`json:"pod_cpu_limit_pct"\`
|
|
226
|
+
IsPodCPULimited bool \`json:"is_pod_cpu_limited"\`
|
|
227
|
+
CPUThreadsUsage []float64 \`json:"cpu_threads_usage"\`
|
|
215
228
|
SystemCPUCount int \`json:"system_cpu_count"\`
|
|
216
229
|
ProcessFilesOpen int32 \`json:"process_files_open"\`
|
|
217
230
|
|
|
231
|
+
TotalMemMB uint64 \`json:"total_mem_mb"\`
|
|
218
232
|
HeapAllocMB uint64 \`json:"heap_alloc_mb"\`
|
|
219
233
|
HeapSysMB uint64 \`json:"heap_sys_mb"\`
|
|
220
234
|
NumGC uint32 \`json:"num_gc"\`
|
|
@@ -222,11 +236,88 @@ type SystemMetrics struct {
|
|
|
222
236
|
Goroutines int \`json:"goroutines"\`
|
|
223
237
|
}
|
|
224
238
|
|
|
239
|
+
func getContainerMemoryLimit() uint64 {
|
|
240
|
+
// Check cgroup v2
|
|
241
|
+
if data, err := os.ReadFile("/sys/fs/cgroup/memory.max"); err == nil {
|
|
242
|
+
val := strings.TrimSpace(string(data))
|
|
243
|
+
if val != "max" && val != "" {
|
|
244
|
+
if limit, err := strconv.ParseUint(val, 10, 64); err == nil {
|
|
245
|
+
return limit
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Check cgroup v1
|
|
250
|
+
if data, err := os.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes"); err == nil {
|
|
251
|
+
val := strings.TrimSpace(string(data))
|
|
252
|
+
if limit, err := strconv.ParseUint(val, 10, 64); err == nil {
|
|
253
|
+
// Some systems report an absurdly high number (e.g. 9223372036854771712) for "no limit"
|
|
254
|
+
if limit < 9000000000000000000 {
|
|
255
|
+
return limit
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return 0
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
func getCgroupCPUUsageNs() (uint64, error) {
|
|
263
|
+
// try v2
|
|
264
|
+
if data, err := os.ReadFile("/sys/fs/cgroup/cpu.stat"); err == nil {
|
|
265
|
+
lines := strings.Split(string(data), "\n")
|
|
266
|
+
for _, line := range lines {
|
|
267
|
+
if strings.HasPrefix(line, "usage_usec") {
|
|
268
|
+
parts := strings.Fields(line)
|
|
269
|
+
if len(parts) == 2 {
|
|
270
|
+
if usec, err := strconv.ParseUint(parts[1], 10, 64); err == nil {
|
|
271
|
+
return usec * 1000, nil // to nanoseconds
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// try v1
|
|
278
|
+
if data, err := os.ReadFile("/sys/fs/cgroup/cpuacct/cpuacct.usage"); err == nil {
|
|
279
|
+
val := strings.TrimSpace(string(data))
|
|
280
|
+
if ns, err := strconv.ParseUint(val, 10, 64); err == nil {
|
|
281
|
+
return ns, nil
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return 0, fmt.Errorf("not found")
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
func getCgroupCPULimitCores() float64 {
|
|
288
|
+
// check v2
|
|
289
|
+
if data, err := os.ReadFile("/sys/fs/cgroup/cpu.max"); err == nil {
|
|
290
|
+
parts := strings.Fields(strings.TrimSpace(string(data)))
|
|
291
|
+
if len(parts) == 2 && parts[0] != "max" {
|
|
292
|
+
max, err1 := strconv.ParseFloat(parts[0], 64)
|
|
293
|
+
period, err2 := strconv.ParseFloat(parts[1], 64)
|
|
294
|
+
if err1 == nil && err2 == nil && period > 0 {
|
|
295
|
+
return max / period
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// check v1
|
|
300
|
+
if quotaData, err := os.ReadFile("/sys/fs/cgroup/cpu/cpu.cfs_quota_us"); err == nil {
|
|
301
|
+
quotaStr := strings.TrimSpace(string(quotaData))
|
|
302
|
+
if quotaStr != "-1" {
|
|
303
|
+
if quota, err := strconv.ParseFloat(quotaStr, 64); err == nil {
|
|
304
|
+
if periodData, err := os.ReadFile("/sys/fs/cgroup/cpu/cpu.cfs_period_us"); err == nil {
|
|
305
|
+
if period, err := strconv.ParseFloat(strings.TrimSpace(string(periodData)), 64); err == nil && period > 0 {
|
|
306
|
+
return quota / period
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return 0
|
|
313
|
+
}
|
|
314
|
+
|
|
225
315
|
func CollectSystemMetrics() SystemMetrics {
|
|
226
316
|
var m runtime.MemStats
|
|
227
317
|
runtime.ReadMemStats(&m)
|
|
228
318
|
|
|
229
319
|
cpuPercent, _ := cpu.Percent(0, false)
|
|
320
|
+
threadsPercent, _ := cpu.Percent(0, true)
|
|
230
321
|
sysCPU := 0.0
|
|
231
322
|
if len(cpuPercent) > 0 {
|
|
232
323
|
sysCPU = cpuPercent[0]
|
|
@@ -241,23 +332,59 @@ func CollectSystemMetrics() SystemMetrics {
|
|
|
241
332
|
openFiles = int32(len(files))
|
|
242
333
|
}
|
|
243
334
|
|
|
335
|
+
vMem, _ := mem.VirtualMemory()
|
|
336
|
+
totalMemMB := uint64(0)
|
|
337
|
+
|
|
338
|
+
// 1. Try Kubernetes / Docker Cgroup Limits first
|
|
339
|
+
cgroupLimitBytes := getContainerMemoryLimit()
|
|
340
|
+
if cgroupLimitBytes > 0 {
|
|
341
|
+
totalMemMB = cgroupLimitBytes / 1024 / 1024
|
|
342
|
+
} else if vMem != nil {
|
|
343
|
+
// 2. Fallback to underlying physical host memory
|
|
344
|
+
totalMemMB = vMem.Total / 1024 / 1024
|
|
345
|
+
}
|
|
346
|
+
|
|
244
347
|
appMetrics := GetGlobalMetrics()
|
|
245
348
|
uptime := time.Since(appMetrics.StartTime)
|
|
246
349
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
350
|
+
uptimeStr := fmt.Sprintf("%d days, %d hours, %d minutes",
|
|
351
|
+
int(uptime.Hours())/24, int(uptime.Hours())%24, int(uptime.Minutes())%60)
|
|
352
|
+
|
|
353
|
+
podCPULimitPct := 0.0
|
|
354
|
+
isPodCPULimited := false
|
|
355
|
+
|
|
356
|
+
limitCores := getCgroupCPULimitCores()
|
|
357
|
+
if limitCores > 0 {
|
|
358
|
+
isPodCPULimited = true
|
|
359
|
+
cgroupCPULock.Lock()
|
|
360
|
+
usageNs, err := getCgroupCPUUsageNs()
|
|
361
|
+
now := time.Now()
|
|
362
|
+
if err == nil {
|
|
363
|
+
if !lastCgroupTime.IsZero() && usageNs > lastCgroupUsageNs {
|
|
364
|
+
timeDelta := float64(now.Sub(lastCgroupTime).Nanoseconds())
|
|
365
|
+
usageDelta := float64(usageNs - lastCgroupUsageNs)
|
|
366
|
+
if timeDelta > 0 {
|
|
367
|
+
coresUsed := usageDelta / timeDelta
|
|
368
|
+
podCPULimitPct = (coresUsed / limitCores) * 100.0
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
lastCgroupUsageNs = usageNs
|
|
372
|
+
lastCgroupTime = now
|
|
373
|
+
}
|
|
374
|
+
cgroupCPULock.Unlock()
|
|
375
|
+
}
|
|
253
376
|
|
|
254
377
|
return SystemMetrics{
|
|
255
378
|
Uptime: uptimeStr,
|
|
256
379
|
StartTime: appMetrics.StartTime.Format(time.RFC1123),
|
|
257
380
|
ProcessCPUUsage: procCPU,
|
|
258
381
|
SystemCPUUsage: sysCPU,
|
|
382
|
+
PodCPULimitPct: podCPULimitPct,
|
|
383
|
+
IsPodCPULimited: isPodCPULimited,
|
|
384
|
+
CPUThreadsUsage: threadsPercent,
|
|
259
385
|
SystemCPUCount: runtime.NumCPU(),
|
|
260
386
|
ProcessFilesOpen: openFiles,
|
|
387
|
+
TotalMemMB: totalMemMB,
|
|
261
388
|
HeapAllocMB: m.HeapAlloc / 1024 / 1024,
|
|
262
389
|
HeapSysMB: m.HeapSys / 1024 / 1024,
|
|
263
390
|
NumGC: m.NumGC,
|
package/go.mod
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module testmod
|
|
2
|
+
|
|
3
|
+
go 1.26.1
|
|
4
|
+
|
|
5
|
+
require (
|
|
6
|
+
filippo.io/edwards25519 v1.1.0 // indirect
|
|
7
|
+
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
|
8
|
+
github.com/google/uuid v1.6.0 // indirect
|
|
9
|
+
github.com/jinzhu/inflection v1.0.0 // indirect
|
|
10
|
+
github.com/jinzhu/now v1.1.5 // indirect
|
|
11
|
+
golang.org/x/text v0.20.0 // indirect
|
|
12
|
+
gorm.io/datatypes v1.2.7 // indirect
|
|
13
|
+
gorm.io/driver/mysql v1.5.6 // indirect
|
|
14
|
+
gorm.io/gorm v1.30.0 // indirect
|
|
15
|
+
)
|
package/go.sum
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
|
2
|
+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
|
3
|
+
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
|
4
|
+
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
|
5
|
+
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
|
6
|
+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
7
|
+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
8
|
+
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
|
9
|
+
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
|
10
|
+
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|
11
|
+
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
|
12
|
+
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
|
13
|
+
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
|
14
|
+
gorm.io/datatypes v1.2.7 h1:ww9GAhF1aGXZY3EB3cJPJ7//JiuQo7DlQA7NNlVaTdk=
|
|
15
|
+
gorm.io/datatypes v1.2.7/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY=
|
|
16
|
+
gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8=
|
|
17
|
+
gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
|
18
|
+
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
|
19
|
+
gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs=
|
|
20
|
+
gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE=
|
package/index.js
CHANGED
|
@@ -216,6 +216,11 @@ Handlebars.registerHelper('isJson', (type) => {
|
|
|
216
216
|
return t === 'json' || t === 'jsonb';
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
+
Handlebars.registerHelper('hasDecimal', (fields) => {
|
|
220
|
+
if (!fields || !Array.isArray(fields)) return false;
|
|
221
|
+
return fields.some(f => f.type === 'BigDecimal');
|
|
222
|
+
});
|
|
223
|
+
|
|
219
224
|
Handlebars.registerHelper('toLowerCase', (str) => {
|
|
220
225
|
if (typeof str !== 'string') return '';
|
|
221
226
|
return str.toLowerCase();
|
|
@@ -235,11 +240,13 @@ Handlebars.registerHelper('toGoType', (type, options) => {
|
|
|
235
240
|
'text': 'string',
|
|
236
241
|
'integer': 'int',
|
|
237
242
|
'int': 'int',
|
|
238
|
-
'float': '
|
|
243
|
+
'float': 'float32',
|
|
244
|
+
'double': 'float64',
|
|
239
245
|
'boolean': 'bool',
|
|
240
246
|
'bool': 'bool',
|
|
247
|
+
'time': 'time.Time',
|
|
241
248
|
'long': 'int64',
|
|
242
|
-
'bigdecimal': '
|
|
249
|
+
'bigdecimal': 'decimal.Decimal',
|
|
243
250
|
'localdate': 'time.Time',
|
|
244
251
|
'instant': 'time.Time',
|
|
245
252
|
'datetime': 'time.Time',
|
|
@@ -662,7 +669,8 @@ program
|
|
|
662
669
|
// 8. Generate Swagger Docs
|
|
663
670
|
await generateSwaggerDocs(config, entities, absoluteOutputDir, openEntities);
|
|
664
671
|
await generatePostmanCollection(config, entities, absoluteOutputDir, openEntities);
|
|
665
|
-
|
|
672
|
+
await generateMQTTTopicsJSON(config, entities, absoluteOutputDir);
|
|
673
|
+
console.log(chalk.green('✅ Swagger API, Postman Collection, and MQTT Dictionary generated!'));
|
|
666
674
|
|
|
667
675
|
// 8.5 Generate Web Docs App
|
|
668
676
|
await generateDocumentation(config, entities, absoluteOutputDir, enums, openEntities);
|
|
@@ -835,9 +843,10 @@ require (
|
|
|
835
843
|
// Sync WebSocket
|
|
836
844
|
await generateWebSocketCode(config, entities, absoluteOutputDir);
|
|
837
845
|
|
|
838
|
-
// Sync Swagger Docs
|
|
846
|
+
// Sync Swagger Docs & MQTT Dictionary
|
|
839
847
|
await generateSwaggerDocs(config, entities, absoluteOutputDir, openEntities);
|
|
840
848
|
await generatePostmanCollection(config, entities, absoluteOutputDir, openEntities);
|
|
849
|
+
await generateMQTTTopicsJSON(config, entities, absoluteOutputDir);
|
|
841
850
|
|
|
842
851
|
// Sync Web Docs App
|
|
843
852
|
await generateDocumentation(config, entities, absoluteOutputDir, enums, openEntities);
|
package/package.json
CHANGED
package/parser/gdl.js
CHANGED
|
@@ -8,7 +8,7 @@ import path from 'path';
|
|
|
8
8
|
* fieldName Type [required] [unique] [text]
|
|
9
9
|
*
|
|
10
10
|
* Supported types:
|
|
11
|
-
* String, Text, Integer, Long, Float, BigDecimal, Boolean, LocalDate, Instant, JSON, JSONB
|
|
11
|
+
* String, Text, Integer, Long, Float, Double, BigDecimal, Boolean, Time, LocalDate, Instant, JSON, JSONB
|
|
12
12
|
*
|
|
13
13
|
* Type overrides in GDL:
|
|
14
14
|
* - `Text` maps to TEXT in DB and string in Go
|
|
@@ -266,9 +266,11 @@ export const toGoType = (type, enums = []) => {
|
|
|
266
266
|
Text: 'string',
|
|
267
267
|
Integer: 'int',
|
|
268
268
|
Long: 'int64',
|
|
269
|
-
Float: '
|
|
270
|
-
|
|
269
|
+
Float: 'float32',
|
|
270
|
+
Double: 'float64',
|
|
271
|
+
BigDecimal: 'decimal.Decimal',
|
|
271
272
|
Boolean: 'bool',
|
|
273
|
+
Time: 'time.Time',
|
|
272
274
|
LocalDate: 'time.Time',
|
|
273
275
|
Instant: 'time.Time',
|
|
274
276
|
JSON: 'datatypes.JSON',
|
|
@@ -291,9 +293,11 @@ export const toLiquibaseType = (field, enums = []) => {
|
|
|
291
293
|
String: 'VARCHAR(255)',
|
|
292
294
|
Integer: 'INT',
|
|
293
295
|
Long: 'BIGINT',
|
|
294
|
-
Float: '
|
|
295
|
-
|
|
296
|
+
Float: 'REAL',
|
|
297
|
+
Double: 'DOUBLE PRECISION',
|
|
298
|
+
BigDecimal: 'NUMERIC(19, 4)',
|
|
296
299
|
Boolean: 'BOOLEAN',
|
|
300
|
+
Time: 'TIME',
|
|
297
301
|
LocalDate: 'DATE',
|
|
298
302
|
Instant: 'TIMESTAMP',
|
|
299
303
|
JSON: 'JSON',
|
|
@@ -41,6 +41,39 @@ metadata JSONB
|
|
|
41
41
|
</div>
|
|
42
42
|
</div>
|
|
43
43
|
|
|
44
|
+
<!-- Comprehensive Example -->
|
|
45
|
+
<div class="bg-slate-900 p-10 rounded-[3rem] border border-slate-800 mb-20 shadow-xl shadow-slate-900/50">
|
|
46
|
+
<h2 class="text-2xl font-black text-white mb-6 m-0 flex items-center">
|
|
47
|
+
<svg class="w-6 h-6 mr-3 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" /></svg>
|
|
48
|
+
Comprehensive Financial Entity Example
|
|
49
|
+
</h2>
|
|
50
|
+
<p class="text-slate-400 mb-6">This real-world example demonstrates the use of high-precision numeric types like <code class="text-emerald-400">Double</code> and <code class="text-emerald-400">BigDecimal</code> alongside standard types, modifiers, and entity annotations.</p>
|
|
51
|
+
|
|
52
|
+
<div class="bg-slate-950 p-6 rounded-2xl border border-slate-800 shadow-inner overflow-x-auto">
|
|
53
|
+
<pre class="bg-transparent p-0 text-emerald-400 font-mono text-sm leading-relaxed whitespace-pre font-bold m-0">
|
|
54
|
+
@Audited
|
|
55
|
+
@Searchable
|
|
56
|
+
entity Transaction {
|
|
57
|
+
uuid id required unique // Maps to UUID
|
|
58
|
+
string(50) transactionId required unique // Maps to VARCHAR(50)
|
|
59
|
+
string currency required // Maps to VARCHAR(255)
|
|
60
|
+
text notes // Maps to TEXT
|
|
61
|
+
int attemptCount // Maps to INTEGER
|
|
62
|
+
long userId required // Maps to BIGINT
|
|
63
|
+
float fee // Maps to REAL and float32
|
|
64
|
+
double exchangeRate // Maps to DOUBLE PRECISION and float64
|
|
65
|
+
bigdecimal amount required // Maps to NUMERIC(19,4) and decimal.Decimal
|
|
66
|
+
bool isInternational // Maps to BOOLEAN
|
|
67
|
+
time cutoffTime // Maps to TIME and time.Time
|
|
68
|
+
datetime processedAt // Maps to TIMESTAMP and time.Time
|
|
69
|
+
instant createdAt // Maps to TIMESTAMP and time.Time
|
|
70
|
+
jsonb metadata // Maps to JSONB
|
|
71
|
+
json rawPayload // Maps to JSON
|
|
72
|
+
}
|
|
73
|
+
</pre>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
44
77
|
<!-- ELITE TYPE REFERENCE -->
|
|
45
78
|
<section class="mb-20">
|
|
46
79
|
<h2 class="text-3xl font-black text-slate-900 mb-8 tracking-tight underline decoration-emerald-500 underline-offset-8">Global Type System Reference</h2>
|
|
@@ -74,6 +107,21 @@ metadata JSONB
|
|
|
74
107
|
<td class="px-6 py-4 font-mono text-slate-400">int64</td>
|
|
75
108
|
<td class="px-6 py-4 font-mono text-slate-400">BIGINT</td>
|
|
76
109
|
</tr>
|
|
110
|
+
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
111
|
+
<td class="px-6 py-4 font-mono font-bold text-emerald-700">float</td>
|
|
112
|
+
<td class="px-6 py-4 font-mono text-slate-400">float32</td>
|
|
113
|
+
<td class="px-6 py-4 font-mono text-slate-400">REAL</td>
|
|
114
|
+
</tr>
|
|
115
|
+
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
116
|
+
<td class="px-6 py-4 font-mono font-bold text-emerald-700">double</td>
|
|
117
|
+
<td class="px-6 py-4 font-mono text-slate-400">float64</td>
|
|
118
|
+
<td class="px-6 py-4 font-mono text-slate-400">DOUBLE PRECISION</td>
|
|
119
|
+
</tr>
|
|
120
|
+
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
121
|
+
<td class="px-6 py-4 font-mono font-bold text-emerald-700">bigdecimal</td>
|
|
122
|
+
<td class="px-6 py-4 font-mono text-slate-400">decimal.Decimal</td>
|
|
123
|
+
<td class="px-6 py-4 font-mono text-slate-400">NUMERIC(19, 4)</td>
|
|
124
|
+
</tr>
|
|
77
125
|
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
78
126
|
<td class="px-6 py-4 font-mono font-bold text-emerald-700">bool / boolean</td>
|
|
79
127
|
<td class="px-6 py-4 font-mono text-slate-400">bool</td>
|
|
@@ -89,6 +137,11 @@ metadata JSONB
|
|
|
89
137
|
<td class="px-6 py-4 font-mono text-slate-400">time.Time</td>
|
|
90
138
|
<td class="px-6 py-4 font-mono text-slate-400">TIMESTAMP</td>
|
|
91
139
|
</tr>
|
|
140
|
+
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
141
|
+
<td class="px-6 py-4 font-mono font-bold text-emerald-700">time</td>
|
|
142
|
+
<td class="px-6 py-4 font-mono text-slate-400">time.Time</td>
|
|
143
|
+
<td class="px-6 py-4 font-mono text-slate-400">TIME</td>
|
|
144
|
+
</tr>
|
|
92
145
|
<tr class="hover:bg-emerald-50/30 transition-colors">
|
|
93
146
|
<td class="px-6 py-4 font-mono font-bold text-emerald-700">uuid</td>
|
|
94
147
|
<td class="px-6 py-4 font-mono text-slate-400">uuid.UUID</td>
|