local ModelBase = class("ModelBase") ModelBase.key = "key" ModelBase.schema = { key = {"string"} } ModelBase.fields = {} -- 数据库字段 field, update 是否立即更新 local string_format = string.format local table_insert = table.insert local table_unpack = table.unpack local assert = assert local next = next local ipairs = ipairs local pairs = pairs local tostring = tostring local tonumber = tonumber local redisproxy = redisproxy local function filterProperties(properties, filter) for i, field in ipairs(filter) do properties[field] = nil end end function ModelBase:ctor(properties) self.isModelBase_ = true -- self.dirtyFields = {} if type(properties) ~= "table" then properties = {} end self:setProperties(properties, true) --缺少的域将设置默认值 end --[[-- 返回对象的 ID 值。 **Returns:** - ID 值 ]] function ModelBase:getKey() local id = self[self.class.key .. "_"] assert(id ~= nil, string_format("%s [%s:getKey()] Invalid key", tostring(self), self.class.__cname)) return id end function ModelBase:load(properties) if not self:isValidKey() then print(string_format("%s [%s:id] should be set before load", tostring(self), self.class.__cname)) return false end if not properties then properties = redisproxy:hgetall(self:getKey()) properties = table.arrayToMap(properties) end if not next(properties) then return false end self:setProperties(properties, true) self:onLoad() return true end --创建model对应的redis数据, 必须已经设置了ID function ModelBase:create() if not self:isValidKey() then print(string_format("%s [%s:key] should be set before create", tostring(self), self.class.__cname)) return nil end --将所有的域都置为dirty, 存储到redis -- for fieldName, update in pairs(self.class.fields) do -- self.dirtyFields[fieldName] = true -- end self:save() self:onCreate() return self end function ModelBase:save() local redisProperties = self:getProperties() local params = {} for fieldName, value in pairs(redisProperties) do -- if self.dirtyFields[fieldName] then local propname = fieldName .. "_" table_insert(params, fieldName) table_insert(params, self[propname]) -- end end if next(params) then redisproxy:hmset(self:getKey(), table_unpack(params)) end end --[[-- 确定对象是否设置了有效的 key。 ]] function ModelBase:isValidKey() local propname = self.class.key .. "_" local key = self[propname] return type(key) == "string" and key ~= "" end --[[-- 修改对象的属性。 NOTE: 如果properties缺少schema中的域, 将用默认值来填充 **Parameters:** - properties: 包含属性值的数组 ]] function ModelBase:setProperties(properties, notWrite) assert(type(properties) == "table", "Invalid properties") -- string_format("%s [%s:setProperties()] Invalid properties", tostring(self), self.class.__cname)) local params = {} for field, schema in pairs(self.class.schema) do local typ, def = table_unpack(schema) local propname = field .. "_" local val = properties[field] or def if val ~= nil then if typ == "number" then val = tonumber(val) end assert(type(val) == typ, string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", tostring(self), self.class.__cname, field, typ, type(val))) self[propname] = val table_insert(params, field) table_insert(params, val) end end if not notWrite and next(params) then redisproxy:hmset(self:getKey(), table_unpack(params)) end end --[[-- 取得对象的属性值。 **Parameters:** - fields: 要取得哪些属性的值,如果未指定该参数,则返回 fields 中设定的属性 - filter: 要从结果中过滤掉哪些属性,如果未指定则不过滤 **Returns:** - 包含属性值的数组 ]] function ModelBase:getProperties(fields, filter) local schema = self.class.schema if type(fields) ~= "table" then fields = table.keys(self.class.fields) end local properties = {} for i, field in ipairs(fields) do local propname = field .. "_" local typ = schema[field][1] local val = self[propname] assert(type(val) == typ, string_format("%s [%s:getProperties()] Type mismatch, %s expected %s, actual is %s", tostring(self), self.class.__cname, field, typ, type(val))) properties[field] = val end if type(filter) == "table" then filterProperties(properties, filter) end return properties end function ModelBase:getProperty(property) if type(property) ~= "string" then return nil end if not self.class.schema[property] then return nil end return self:getProperties({property})[property] end function ModelBase:setProperty(property, value, update) if not self.class.schema[property] then print(string_format("%s [%s:setProperty()] Invalid property : %s", tostring(self), self.class.__cname, property)) return end local typ, def = table_unpack(self.class.schema[property]) local propname = property .. "_" if typ == "number" then value = tonumber(value) end assert(type(value) == typ, string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", tostring(self), self.class.__cname, property, typ, type(value))) self[propname] = value if self.class.fields[property] or update then redisproxy:hset(self:getKey(), property, value) else -- self.dirtyFields[property] = true -- record the fields been modified end end function ModelBase:incrProperty(property, value, update) if not self.class.schema[property] then print(string_format("%s [%s:setProperty()] Invalid property : %s", tostring(self), self.class.__cname, property)) return end local typ, def = table_unpack(self.class.schema[property]) local propname = property .. "_" if typ == "number" then value = tonumber(value) end assert(type(value) == typ, string_format("%s [%s:setProperties()] Type mismatch, %s expected %s, actual is %s", tostring(self), self.class.__cname, property, typ, type(value))) self[propname] = self[propname] + value if self.class.fields[property] or update then return redisproxy:hincrby(self:getKey(), property, value) else -- self.dirtyFields[property] = true -- record the fields been modified end end function ModelBase:onLoad() end function ModelBase:onCreate() end return ModelBase