Files
srdb/examples/complex/main.go

692 lines
23 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"time"
"code.tczkiot.com/wlw/srdb"
"github.com/shopspring/decimal"
)
// ========== 嵌套结构体定义 ==========
// Location 位置信息(嵌套结构体)
type Location struct {
Country string `json:"country"`
Province string `json:"province"`
City string `json:"city"`
Address string `json:"address"`
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
}
// NetworkConfig 网络配置(嵌套结构体)
type NetworkConfig struct {
SSID string `json:"ssid"`
Password string `json:"password"`
IPAddress string `json:"ip_address"`
Gateway string `json:"gateway"`
DNS string `json:"dns"`
UseStaticIP bool `json:"use_static_ip"`
}
// Sensor 传感器信息(用于切片)
type Sensor struct {
Type string `json:"type"` // 传感器类型
Model string `json:"model"` // 型号
Value float64 `json:"value"` // 当前值
Unit string `json:"unit"` // 单位
MinValue float64 `json:"min_value"` // 最小值
MaxValue float64 `json:"max_value"` // 最大值
Precision int `json:"precision"` // 精度
SamplingRate int `json:"sampling_rate"` // 采样率
Enabled bool `json:"enabled"` // 是否启用
}
// MaintenanceRecord 维护记录(用于切片)
type MaintenanceRecord struct {
Date string `json:"date"` // 维护日期
Technician string `json:"technician"` // 技术员
Type string `json:"type"` // 维护类型
Description string `json:"description"` // 描述
Cost float64 `json:"cost"` // 费用
NextDate string `json:"next_date"` // 下次维护日期
}
// ========== 主结构体定义 ==========
// ComplexDevice 复杂设备记录(包含所有复杂场景)
type ComplexDevice struct {
// ========== 基本字段 ==========
DeviceID string `srdb:"device_id;indexed;comment:设备ID"`
Name string `srdb:"name;comment:设备名称"`
Model string `srdb:"model;comment:设备型号"`
// ========== Nullable 字段(指针类型)==========
SerialNumber *string `srdb:"serial_number;nullable;comment:序列号(可选)"`
Manufacturer *string `srdb:"manufacturer;nullable;comment:制造商(可选)"`
Description *string `srdb:"description;nullable;comment:描述(可选)"`
WarrantyEnd *time.Time `srdb:"warranty_end;nullable;comment:保修截止日期(可选)"`
LastMaintenance *time.Time `srdb:"last_maintenance;nullable;comment:上次维护时间(可选)"`
MaxPower *float32 `srdb:"max_power;nullable;comment:最大功率(可选)"`
Weight *float64 `srdb:"weight;nullable;comment:重量(可选)"`
Voltage *int32 `srdb:"voltage;nullable;comment:电压(可选)"`
Price *decimal.Decimal `srdb:"price;nullable;comment:价格(可选)"`
// ========== 所有基本类型 ==========
// 有符号整数
Signal int `srdb:"signal;comment:信号强度"`
ErrorCode int8 `srdb:"error_code;comment:错误码"`
Temperature int16 `srdb:"temperature;comment:温度(℃*10"`
Counter int32 `srdb:"counter;comment:计数器"`
TotalBytes int64 `srdb:"total_bytes;comment:总字节数"`
// 无符号整数
Flags uint `srdb:"flags;comment:标志位"`
Status uint8 `srdb:"status;comment:状态码"`
Port uint16 `srdb:"port;comment:端口号"`
SessionID uint32 `srdb:"session_id;comment:会话ID"`
Timestamp uint64 `srdb:"timestamp;comment:时间戳"`
// 浮点数
Humidity float32 `srdb:"humidity;comment:湿度"`
Latitude float64 `srdb:"latitude;comment:纬度"`
Longitude float64 `srdb:"longitude;comment:经度"`
// 布尔
IsOnline bool `srdb:"is_online;indexed;comment:是否在线"`
IsActivated bool `srdb:"is_activated;comment:是否激活"`
// 特殊类型
BatteryLevel byte `srdb:"battery_level;comment:电池电量"`
Grade rune `srdb:"grade;comment:等级"`
TotalPrice decimal.Decimal `srdb:"total_price;comment:总价"`
CreatedAt time.Time `srdb:"created_at;comment:创建时间"`
Uptime time.Duration `srdb:"uptime;comment:运行时长"`
// ========== 嵌套结构体Object==========
Location Location `srdb:"location;comment:位置信息(嵌套结构体)"`
NetworkConfig NetworkConfig `srdb:"network_config;comment:网络配置(嵌套结构体)"`
// ========== 结构体切片Array==========
Sensors []Sensor `srdb:"sensors;comment:传感器列表(结构体切片)"`
MaintenanceRecords []MaintenanceRecord `srdb:"maintenance_records;comment:维护记录(结构体切片)"`
// ========== 基本类型切片 ==========
Tags []string `srdb:"tags;comment:标签列表"`
AlertCodes []int32 `srdb:"alert_codes;comment:告警代码列表"`
HistoryReadings []float64 `srdb:"history_readings;comment:历史读数"`
// ========== 简单 MapObject==========
Metadata map[string]any `srdb:"metadata;comment:元数据"`
CustomSettings map[string]any `srdb:"custom_settings;comment:自定义设置"`
}
func main() {
// 命令行参数
dataDir := flag.String("dir", "./data", "数据存储目录")
clean := flag.Bool("clean", false, "运行前清理数据目录")
flag.Parse()
fmt.Println("=============================================================")
fmt.Println(" SRDB 复杂类型系统演示Nullable + 嵌套结构体 + 结构体切片)")
fmt.Println("=============================================================\n")
// 准备数据目录
absDir, err := filepath.Abs(*dataDir)
if err != nil {
fmt.Printf("❌ 无效的目录路径: %v\n", err)
os.Exit(1)
}
if *clean {
fmt.Printf("🧹 清理数据目录: %s\n", absDir)
os.RemoveAll(absDir)
}
fmt.Printf("📁 数据目录: %s\n\n", absDir)
// ========== 步骤 1: 从结构体生成 Schema ==========
fmt.Println("【步骤 1】从结构体自动生成 Schema")
fmt.Println("─────────────────────────────────────────────────────")
fields, err := srdb.StructToFields(ComplexDevice{})
if err != nil {
fmt.Printf("❌ 失败: %v\n", err)
os.Exit(1)
}
fmt.Printf("✅ 成功生成 %d 个字段\n\n", len(fields))
// 统计字段类型
nullableCount := 0
objectCount := 0
arrayCount := 0
for _, field := range fields {
if field.Nullable {
nullableCount++
}
if field.Type.String() == "object" {
objectCount++
}
if field.Type.String() == "array" {
arrayCount++
}
}
fmt.Println("字段统计:")
fmt.Printf(" • 总字段数: %d\n", len(fields))
fmt.Printf(" • Nullable 字段: %d 个(使用指针)\n", nullableCount)
fmt.Printf(" • Object 字段: %d 个(结构体/map\n", objectCount)
fmt.Printf(" • Array 字段: %d 个(切片)\n", arrayCount)
// ========== 步骤 2: 创建表 ==========
fmt.Println("\n【步骤 2】创建数据表")
fmt.Println("─────────────────────────────────────────────────────")
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: absDir,
Name: "complex_devices",
Fields: fields,
})
if err != nil {
fmt.Printf("❌ 创建表失败: %v\n", err)
os.Exit(1)
}
defer table.Close()
fmt.Println("✅ 表 'complex_devices' 创建成功")
// ========== 步骤 3: 插入完整数据 ==========
fmt.Println("\n【步骤 3】插入测试数据")
fmt.Println("─────────────────────────────────────────────────────")
// 准备辅助变量
serialNum := "SN-2025-001-ALPHA"
manufacturer := "智能科技有限公司"
description := "高性能工业级环境监测站,支持多种传感器接入"
warrantyEnd := time.Now().AddDate(3, 0, 0) // 3年保修
lastMaint := time.Now().Add(-30 * 24 * time.Hour) // 30天前维护
maxPower := float32(500.5)
weight := 12.5
voltage := int32(220)
price := decimal.NewFromFloat(9999.99)
// 数据1: 完整填充(包含所有 Nullable 字段)
device1 := map[string]any{
// 基本字段
"device_id": "COMPLEX-DEV-001",
"name": "智能环境监测站 Pro",
"model": "ENV-MONITOR-PRO-X1",
// Nullable 字段(全部有值)
"serial_number": serialNum,
"manufacturer": manufacturer,
"description": description,
"warranty_end": warrantyEnd,
"last_maintenance": lastMaint,
"max_power": maxPower,
"weight": weight,
"voltage": voltage,
"price": price,
// 基本类型
"signal": -55,
"error_code": int8(0),
"temperature": int16(235), // 23.5°C
"counter": int32(12345),
"total_bytes": int64(1024 * 1024 * 500),
"flags": uint(0x0F),
"status": uint8(200),
"port": uint16(8080),
"session_id": uint32(987654321),
"timestamp": uint64(time.Now().Unix()),
"humidity": float32(65.5),
"latitude": 39.904200,
"longitude": 116.407396,
"is_online": true,
"is_activated": true,
"battery_level": byte(85),
"grade": rune('S'),
"total_price": decimal.NewFromFloat(15999.99),
"created_at": time.Now(),
"uptime": 72 * time.Hour,
// 嵌套结构体
"location": Location{
Country: "中国",
Province: "北京市",
City: "朝阳区",
Address: "建国路88号",
Lat: 39.904200,
Lng: 116.407396,
},
"network_config": NetworkConfig{
SSID: "SmartDevice-5G",
Password: "******",
IPAddress: "192.168.1.100",
Gateway: "192.168.1.1",
DNS: "8.8.8.8",
UseStaticIP: true,
},
// 结构体切片
"sensors": []Sensor{
{
Type: "temperature",
Model: "DHT22",
Value: 23.5,
Unit: "°C",
MinValue: -40.0,
MaxValue: 80.0,
Precision: 1,
SamplingRate: 1000,
Enabled: true,
},
{
Type: "humidity",
Model: "DHT22",
Value: 65.5,
Unit: "%",
MinValue: 0.0,
MaxValue: 100.0,
Precision: 1,
SamplingRate: 1000,
Enabled: true,
},
{
Type: "pressure",
Model: "BMP280",
Value: 1013.25,
Unit: "hPa",
MinValue: 300.0,
MaxValue: 1100.0,
Precision: 2,
SamplingRate: 500,
Enabled: true,
},
},
"maintenance_records": []MaintenanceRecord{
{
Date: "2024-12-01",
Technician: "张工",
Type: "定期维护",
Description: "清洁传感器、检查线路、更新固件",
Cost: 500.00,
NextDate: "2025-03-01",
},
{
Date: "2024-09-15",
Technician: "李工",
Type: "故障维修",
Description: "更换损坏的温度传感器",
Cost: 800.00,
NextDate: "2024-12-01",
},
},
// 基本类型切片
"tags": []string{"industrial", "outdoor", "monitoring", "iot", "smart-city"},
"alert_codes": []int32{1001, 2003, 3005, 4002},
"history_readings": []float64{23.1, 23.3, 23.5, 23.7, 23.9, 24.0},
// Map
"metadata": map[string]any{
"install_date": "2024-01-15",
"firmware_version": "v2.3.1",
"hardware_revision": "Rev-C",
"certification": []string{"CE", "FCC", "RoHS"},
},
"custom_settings": map[string]any{
"auto_calibrate": true,
"report_interval": 60,
"alert_threshold": 85.0,
"debug_mode": false,
},
}
err = table.Insert(device1)
if err != nil {
fmt.Printf("❌ 插入数据1失败: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ 数据1插入成功: " + device1["name"].(string))
fmt.Println(" 包含: 9个Nullable字段全部有值")
fmt.Println(" 包含: 2个嵌套结构体 + 2个结构体切片")
// Debug: 检查插入后的记录数
count1, _ := table.Query().Rows()
c1 := 0
for count1.Next() {
c1++
}
count1.Close()
fmt.Printf(" 🔍 插入后表中有 %d 条记录\n", c1)
// 数据2: 部分 Nullable 字段为 nil
device2 := map[string]any{
// 基本字段
"device_id": "COMPLEX-DEV-002",
"name": "简易温湿度传感器",
"model": "TEMP-SENSOR-LITE",
// Nullable 字段(部分为 nil
"serial_number": "SN-2025-002-BETA",
"manufacturer": "普通传感器公司",
"description": nil, // NULL
"warranty_end": nil, // NULL
"last_maintenance": nil, // NULL
"max_power": nil, // NULL
"weight": nil, // NULL
"voltage": nil, // NULL
"price": nil, // NULL
// 基本类型
"signal": -70,
"error_code": int8(0),
"temperature": int16(220),
"counter": int32(500),
"total_bytes": int64(1024 * 1024 * 10),
"flags": uint(0x03),
"status": uint8(100),
"port": uint16(8081),
"session_id": uint32(123456789),
"timestamp": uint64(time.Now().Unix()),
"humidity": float32(55.0),
"latitude": 39.900000,
"longitude": 116.400000,
"is_online": false,
"is_activated": true,
"battery_level": byte(30),
"grade": rune('B'),
"total_price": decimal.NewFromFloat(299.99),
"created_at": time.Now().Add(-7 * 24 * time.Hour),
"uptime": 168 * time.Hour,
// 嵌套结构体
"location": Location{
Country: "中国",
Province: "上海市",
City: "浦东新区",
Address: "世纪大道123号",
Lat: 31.235929,
Lng: 121.506058,
},
"network_config": NetworkConfig{
SSID: "SmartDevice-2.4G",
Password: "******",
IPAddress: "192.168.1.101",
Gateway: "192.168.1.1",
DNS: "114.114.114.114",
UseStaticIP: false,
},
// 结构体切片(较少的元素)
"sensors": []Sensor{
{
Type: "temperature",
Model: "DS18B20",
Value: 22.0,
Unit: "°C",
MinValue: -55.0,
MaxValue: 125.0,
Precision: 0,
SamplingRate: 500,
Enabled: true,
},
},
"maintenance_records": []MaintenanceRecord{},
// 基本类型切片
"tags": []string{"indoor", "basic"},
"alert_codes": []int32{},
"history_readings": []float64{21.5, 21.8, 22.0},
// Map
"metadata": map[string]any{
"install_date": "2025-01-01",
"firmware_version": "v1.0.0",
},
"custom_settings": map[string]any{
"report_interval": 120,
},
}
err = table.Insert(device2)
if err != nil {
fmt.Printf("❌ 插入数据2失败: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ 数据2插入成功: " + device2["name"].(string))
fmt.Println(" 包含: 9个Nullable字段6个为nil")
fmt.Println(" 包含: 较少的结构体切片元素")
// Debug: 检查插入后的记录数
count2, _ := table.Query().Rows()
c2 := 0
for count2.Next() {
c2++
}
count2.Close()
fmt.Printf(" 🔍 插入后表中有 %d 条记录\n", c2)
// 数据3: 所有 Nullable 字段为 nil
device3 := map[string]any{
// 基本字段
"device_id": "COMPLEX-DEV-003",
"name": "最小配置设备",
"model": "MIN-CONFIG",
// Nullable 字段(全部为 nil
"serial_number": nil,
"manufacturer": nil,
"description": nil,
"warranty_end": nil,
"last_maintenance": nil,
"max_power": nil,
"weight": nil,
"voltage": nil,
"price": nil,
// 基本类型(最小值/默认值)
"signal": -90,
"error_code": int8(-1),
"temperature": int16(0),
"counter": int32(0),
"total_bytes": int64(0),
"flags": uint(0),
"status": uint8(0),
"port": uint16(0),
"session_id": uint32(0),
"timestamp": uint64(0),
"humidity": float32(0.0),
"latitude": 0.0,
"longitude": 0.0,
"is_online": false,
"is_activated": false,
"battery_level": byte(0),
"grade": rune('C'),
"total_price": decimal.Zero,
"created_at": time.Unix(0, 0),
"uptime": 0 * time.Second,
// 嵌套结构体(空值)
"location": Location{},
"network_config": NetworkConfig{},
// 结构体切片(空切片)
"sensors": []Sensor{},
"maintenance_records": []MaintenanceRecord{},
// 基本类型切片(空切片)
"tags": []string{},
"alert_codes": []int32{},
"history_readings": []float64{},
// Map空map
"metadata": map[string]any{},
"custom_settings": map[string]any{},
}
err = table.Insert(device3)
if err != nil {
fmt.Printf("❌ 插入数据3失败: %v\n", err)
os.Exit(1)
}
fmt.Println("✅ 数据3插入成功: " + device3["name"].(string))
fmt.Println(" 包含: 9个Nullable字段全部为nil")
fmt.Println(" 包含: 所有切片为空")
// Debug: 检查插入后的记录数
count3, _ := table.Query().Rows()
c3 := 0
for count3.Next() {
c3++
}
count3.Close()
fmt.Printf(" 🔍 插入后表中有 %d 条记录\n", c3)
// ========== 步骤 4: 查询并展示 ==========
fmt.Println("\n【步骤 4】查询并验证数据")
fmt.Println("─────────────────────────────────────────────────────")
// Debug: 直接检查表的记录数
debugRows, _ := table.Query().Rows()
debugCount := 0
for debugRows.Next() {
debugCount++
}
debugRows.Close()
fmt.Printf("🔍 调试: 表中实际有 %d 条记录\n\n", debugCount)
rows, err := table.Query().OrderBy("_seq").Rows()
if err != nil {
fmt.Printf("❌ 查询失败: %v\n", err)
os.Exit(1)
}
defer rows.Close()
count := 0
for rows.Next() {
row := rows.Row()
data := row.Data()
count++
fmt.Printf("\n╔══════════════════ 设备 #%d (seq=%d) ══════════════════╗\n", count, row.Seq())
fmt.Printf("║ ID: %-53s ║\n", data["device_id"])
fmt.Printf("║ 名称: %-51s ║\n", data["name"])
fmt.Printf("║ 型号: %-51s ║\n", data["model"])
// Nullable 字段展示
fmt.Printf("╟────────────────── Nullable 字段 ─────────────────────╢\n")
if data["serial_number"] != nil {
fmt.Printf("║ 序列号: %-47s ║\n", data["serial_number"])
} else {
fmt.Printf("║ 序列号: <未设置>%40s ║\n", "")
}
if data["manufacturer"] != nil {
fmt.Printf("║ 制造商: %-47s ║\n", data["manufacturer"])
} else {
fmt.Printf("║ 制造商: <未设置>%40s ║\n", "")
}
if data["price"] != nil {
price := data["price"].(decimal.Decimal)
fmt.Printf("║ 价格: ¥%-47s ║\n", price.StringFixed(2))
} else {
fmt.Printf("║ 价格: <未设置>%42s ║\n", "")
}
if data["warranty_end"] != nil {
warrantyEnd := data["warranty_end"].(time.Time)
fmt.Printf("║ 保修截止: %-43s ║\n", warrantyEnd.Format("2006-01-02"))
} else {
fmt.Printf("║ 保修截止: <未设置>%38s ║\n", "")
}
// 嵌套结构体展示
fmt.Printf("╟───────────────── 嵌套结构体 ─────────────────────╢\n")
location := data["location"].(map[string]any)
fmt.Printf("║ 位置: %s %s %s%*s ║\n",
location["country"], location["province"], location["city"],
37-len(fmt.Sprint(location["country"], location["province"], location["city"])), "")
fmt.Printf("║ 地址: %-43v ║\n", location["address"])
networkCfg := data["network_config"].(map[string]any)
fmt.Printf("║ 网络: SSID=%v, IP=%v%*s ║\n",
networkCfg["ssid"], networkCfg["ip_address"],
27-len(fmt.Sprint(networkCfg["ssid"], networkCfg["ip_address"])), "")
// 结构体切片展示
fmt.Printf("╟───────────────── 结构体切片 ──────────────────────╢\n")
sensors := data["sensors"].([]any)
fmt.Printf("║ 传感器数量: %d 个%39s ║\n", len(sensors), "")
for i, s := range sensors {
sensor := s.(map[string]any)
fmt.Printf("║ [%d] %s: %.1f %s (型号: %s)%*s ║\n",
i+1, sensor["type"], sensor["value"], sensor["unit"], sensor["model"],
20-len(fmt.Sprint(sensor["type"], sensor["model"])), "")
}
maintRecords := data["maintenance_records"].([]any)
fmt.Printf("║ 维护记录: %d 条%40s ║\n", len(maintRecords), "")
for i, m := range maintRecords {
maint := m.(map[string]any)
fmt.Printf("║ [%d] %s - %s (¥%.2f)%*s ║\n",
i+1, maint["date"], maint["type"], maint["cost"],
22-len(fmt.Sprint(maint["date"], maint["type"])), "")
}
// 基本类型切片
fmt.Printf("╟───────────────── 基本类型切片 ────────────────────╢\n")
tags := data["tags"].([]any)
fmt.Printf("║ 标签: %d 个 %v%*s ║\n",
len(tags), tags,
45-len(fmt.Sprint(tags)), "")
fmt.Println("╚═════════════════════════════════════════════════════════╝")
}
if count != 3 {
fmt.Printf("\n❌ 预期 3 条记录,实际 %d 条\n", count)
os.Exit(1)
}
// ========== 总结 ==========
fmt.Println("\n\n=============================================================")
fmt.Println(" ✅ 所有复杂类型测试通过!")
fmt.Println("=============================================================")
fmt.Println("\n📊 功能验证:")
fmt.Println(" ✓ Nullable 字段(指针类型)")
fmt.Println(" - 数据1: 9个Nullable字段全部有值")
fmt.Println(" - 数据2: 9个Nullable字段部分为nil")
fmt.Println(" - 数据3: 9个Nullable字段全部为nil")
fmt.Println("\n ✓ 嵌套结构体Object")
fmt.Println(" - Location: 6个字段的位置信息结构体")
fmt.Println(" - NetworkConfig: 6个字段的网络配置结构体")
fmt.Println("\n ✓ 结构体切片Array of Struct")
fmt.Println(" - Sensors: 传感器列表每个9个字段")
fmt.Println(" - MaintenanceRecords: 维护记录列表每个6个字段")
fmt.Println("\n ✓ 基本类型切片")
fmt.Println(" - []string: 标签列表")
fmt.Println(" - []int32: 告警代码列表")
fmt.Println(" - []float64: 历史读数")
fmt.Println("\n ✓ Map类型")
fmt.Println(" - metadata: 元数据信息")
fmt.Println(" - custom_settings: 自定义设置")
fmt.Println("\n💡 关键特性:")
fmt.Println(" • 指针类型自动识别为Nullable")
fmt.Println(" • 嵌套结构体自动转JSON")
fmt.Println(" • 结构体切片自动序列化")
fmt.Println(" • nil值正确处理和展示")
fmt.Println(" • 空切片和空map正确存储")
fmt.Printf("\n📁 数据已保存到: %s\n", absDir)
}