Skip to content
Bruce edited this page Sep 21, 2025 · 1 revision

sidebar_position: 12

工具

Lua table schema validate

Lua作为脚本语言,数据类型是动态的,并且只有一种数据结构table,可以表示HashTable数组,灵活性比较高。对于业务逻辑,在结构嵌套比较复杂的时候,编写代码时很容易写错,并且不易察觉 ,特别是需要落地的数据,通常需要比较严格地定义数据结构。moon提供了数据合法性检测库lua_schema,通过proto描述文件生成数据校验结构的方式,来校验逻辑中的指定的table结构,用于在开发期间,验证数据,提前发现错误。

syntax = "proto3";

//特殊类型array_XXXX,用于代码提示,描述pb无法表达的结构 {[1]={1,2,3,4,5},[2]={1,2,3,4,5}}
message array_int64
{
	repeated int64 data = 1;
}

message array_int32
{
	repeated int32 data = 1;
}

message ItemData
{
	int32 id = 1;//道具id
	int64 count = 2;//道具数量
	Reward reward = 3;//test nested
}

message UserData
{
	int64           uid              	 	= 1;	//玩家uid
    string          name            	 	= 3;	//玩家名字
    int32          level            	 	= 4;	//玩家等级
    repeated ItemData itemlist	    = 5;   //玩家道具列表
}

message Reward
{
	int32 type = 1;//
	int32 rewardtimes = 2;//
	int32 buyrewardtimes = 3;//
}
local moon = require("moon")
local schema = require("schema")
local json = require("json")

---加载根据proto生成的结构定义
local proto_define = [[
    {
        "array_int64": {
            "data": {
                "container": "array",
                "value_type": "int64",
                "value_index": "1"
            }
        },
        "UserData": {
            "uid": {
                "value_type": "int64",
                "value_index": "2",
                "comment": "玩家uid"
            },
            "name": {
                "value_type": "string",
                "value_index": "3",
                "comment": "玩家名字"
            },
            "level": {
                "value_type": "int32",
                "value_index": "4",
                "comment": "玩家等级"
            },
            "itemlist": {
                "container": "object",
                "key_type": "int32",
                "value_type": "ItemData",
                "value_index": "11",
                "comment": "道具列表"
            },
            "taskrewardgetlist": {
                "container": "object",
                "key_type": "int32",
                "value_type": "array_int64",
                "value_index": "78",
                "comment": "已领取任务奖励id缓存"
            }
        },
        "ItemData": {
            "id": {
                "value_type": "int32",
                "value_index": "1",
                "comment": "道具id"
            },
            "count": {
                "value_type": "int64",
                "value_index": "2",
                "comment": "道具数量"
            },
            "reward": {
                "value_type": "Reward",
                "value_index": "3",
                "comment": "test"
            }
        },
        "Reward": {
            "type": {
                "value_type": "int32",
                "value_index": "1",
                "comment": "怪物类型"
            },
            "rewardtimes": {
                "value_type": "int32",
                "value_index": "2",
                "comment": "已奖励次数"
            },
            "buyrewardtimes": {
                "value_type": "int32",
                "value_index": "3",
                "comment": "钻石购买已奖励次数"
            }
        }
    }
]]

-- load once then shared by other services
schema.load(json.decode(proto_define))

print(pcall(schema.validate, "UserData", {name = 123}))
print(pcall(schema.validate, "UserData", {level = 1.234}))
print(pcall(schema.validate, "UserData", {taskrewardgetlist = {[1] = {1,2,3,false}}}))
print(pcall(schema.validate, "UserData", {itemlist = {a ="123"}}))
print(pcall(schema.validate, "UserData", {itemlist = {1,2,3}}))
print(pcall(schema.validate, "UserData", {itemlist = {[1] = {a= 123}}}))
print(pcall(schema.validate, "UserData", {itemlist = {[1] = {id= 123, count = 123, reward = {type = 123, buyrewardtimes= false, rewardtimes = 100}}}}))

--[[
2023-08-15 20:40:20.787 | :01000001 | INFO  | false     'UserData.name' string expected, got number, value '123'. trace: UserData.name  (example_proto_verify.lua:84)
2023-08-15 20:40:20.787 | :01000001 | INFO  | false     'UserData.level' int32 expected, got number, value '1.234'. trace: UserData.level       (example_proto_verify.lua:85)
2023-08-15 20:40:20.787 | :01000001 | INFO  | false     'array_int64.data.4' int64 expected, got boolean. trace: UserData.taskrewardgetlist.1.data.4    (example_proto_verify.lua:86)
2023-08-15 20:40:20.787 | :01000001 | INFO  | false     'UserData.itemlist.$key' int32 expected, got string. trace: UserData.itemlist.a (example_proto_verify.lua:87)
2023-08-15 20:40:20.788 | :01000001 | INFO  | false     'ItemData' table expected, got number. trace: UserData.itemlist.1       (example_proto_verify.lua:88)
2023-08-15 20:40:20.788 | :01000001 | INFO  | false     Attemp to index undefined field: 'ItemData.a'. trace: UserData.itemlist.1.a     (example_proto_verify.lua:89)
2023-08-15 20:40:20.788 | :01000001 | INFO  | false     'Reward.buyrewardtimes' int32 expected, got boolean, value 'false'. trace: UserData.itemlist.1.reward.buyrewardtimes    (example_proto_verify.lua:90) 
]]

Clone this wiki locally