annotate Libs/AceDB-3.0/AceDB-3.0.lua @ 0:c6ff7ba0e8f6

Reasonably functional now. Cleaning up some stuff which might have to be reverted.
author Zerotorescue
date Thu, 07 Oct 2010 17:17:43 +0200
parents
children
rev   line source
Zerotorescue@0 1 --- **AceDB-3.0** manages the SavedVariables of your addon.
Zerotorescue@0 2 -- It offers profile management, smart defaults and namespaces for modules.\\
Zerotorescue@0 3 -- Data can be saved in different data-types, depending on its intended usage.
Zerotorescue@0 4 -- The most common data-type is the `profile` type, which allows the user to choose
Zerotorescue@0 5 -- the active profile, and manage the profiles of all of his characters.\\
Zerotorescue@0 6 -- The following data types are available:
Zerotorescue@0 7 -- * **char** Character-specific data. Every character has its own database.
Zerotorescue@0 8 -- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
Zerotorescue@0 9 -- * **class** Class-specific data. All of the players characters of the same class share this database.
Zerotorescue@0 10 -- * **race** Race-specific data. All of the players characters of the same race share this database.
Zerotorescue@0 11 -- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
Zerotorescue@0 12 -- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
Zerotorescue@0 13 -- * **global** Global Data. All characters on the same account share this database.
Zerotorescue@0 14 -- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
Zerotorescue@0 15 --
Zerotorescue@0 16 -- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
Zerotorescue@0 17 -- of the DBObjectLib listed here. \\
Zerotorescue@0 18 -- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
Zerotorescue@0 19 -- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
Zerotorescue@0 20 -- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
Zerotorescue@0 21 --
Zerotorescue@0 22 -- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
Zerotorescue@0 23 --
Zerotorescue@0 24 -- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
Zerotorescue@0 25 --
Zerotorescue@0 26 -- @usage
Zerotorescue@0 27 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
Zerotorescue@0 28 --
Zerotorescue@0 29 -- -- declare defaults to be used in the DB
Zerotorescue@0 30 -- local defaults = {
Zerotorescue@0 31 -- profile = {
Zerotorescue@0 32 -- setting = true,
Zerotorescue@0 33 -- }
Zerotorescue@0 34 -- }
Zerotorescue@0 35 --
Zerotorescue@0 36 -- function MyAddon:OnInitialize()
Zerotorescue@0 37 -- -- Assuming the .toc says ## SavedVariables: MyAddonDB
Zerotorescue@0 38 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
Zerotorescue@0 39 -- end
Zerotorescue@0 40 -- @class file
Zerotorescue@0 41 -- @name AceDB-3.0.lua
Zerotorescue@0 42 -- @release $Id: AceDB-3.0.lua 940 2010-06-19 08:01:47Z nevcairiel $
Zerotorescue@0 43 local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 21
Zerotorescue@0 44 local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
Zerotorescue@0 45
Zerotorescue@0 46 if not AceDB then return end -- No upgrade needed
Zerotorescue@0 47
Zerotorescue@0 48 -- Lua APIs
Zerotorescue@0 49 local type, pairs, next, error = type, pairs, next, error
Zerotorescue@0 50 local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
Zerotorescue@0 51
Zerotorescue@0 52 -- WoW APIs
Zerotorescue@0 53 local _G = _G
Zerotorescue@0 54
Zerotorescue@0 55 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
Zerotorescue@0 56 -- List them here for Mikk's FindGlobals script
Zerotorescue@0 57 -- GLOBALS: LibStub
Zerotorescue@0 58
Zerotorescue@0 59 AceDB.db_registry = AceDB.db_registry or {}
Zerotorescue@0 60 AceDB.frame = AceDB.frame or CreateFrame("Frame")
Zerotorescue@0 61
Zerotorescue@0 62 local CallbackHandler
Zerotorescue@0 63 local CallbackDummy = { Fire = function() end }
Zerotorescue@0 64
Zerotorescue@0 65 local DBObjectLib = {}
Zerotorescue@0 66
Zerotorescue@0 67 --[[-------------------------------------------------------------------------
Zerotorescue@0 68 AceDB Utility Functions
Zerotorescue@0 69 ---------------------------------------------------------------------------]]
Zerotorescue@0 70
Zerotorescue@0 71 -- Simple shallow copy for copying defaults
Zerotorescue@0 72 local function copyTable(src, dest)
Zerotorescue@0 73 if type(dest) ~= "table" then dest = {} end
Zerotorescue@0 74 if type(src) == "table" then
Zerotorescue@0 75 for k,v in pairs(src) do
Zerotorescue@0 76 if type(v) == "table" then
Zerotorescue@0 77 -- try to index the key first so that the metatable creates the defaults, if set, and use that table
Zerotorescue@0 78 v = copyTable(v, dest[k])
Zerotorescue@0 79 end
Zerotorescue@0 80 dest[k] = v
Zerotorescue@0 81 end
Zerotorescue@0 82 end
Zerotorescue@0 83 return dest
Zerotorescue@0 84 end
Zerotorescue@0 85
Zerotorescue@0 86 -- Called to add defaults to a section of the database
Zerotorescue@0 87 --
Zerotorescue@0 88 -- When a ["*"] default section is indexed with a new key, a table is returned
Zerotorescue@0 89 -- and set in the host table. These tables must be cleaned up by removeDefaults
Zerotorescue@0 90 -- in order to ensure we don't write empty default tables.
Zerotorescue@0 91 local function copyDefaults(dest, src)
Zerotorescue@0 92 -- this happens if some value in the SV overwrites our default value with a non-table
Zerotorescue@0 93 --if type(dest) ~= "table" then return end
Zerotorescue@0 94 for k, v in pairs(src) do
Zerotorescue@0 95 if k == "*" or k == "**" then
Zerotorescue@0 96 if type(v) == "table" then
Zerotorescue@0 97 -- This is a metatable used for table defaults
Zerotorescue@0 98 local mt = {
Zerotorescue@0 99 -- This handles the lookup and creation of new subtables
Zerotorescue@0 100 __index = function(t,k)
Zerotorescue@0 101 if k == nil then return nil end
Zerotorescue@0 102 local tbl = {}
Zerotorescue@0 103 copyDefaults(tbl, v)
Zerotorescue@0 104 rawset(t, k, tbl)
Zerotorescue@0 105 return tbl
Zerotorescue@0 106 end,
Zerotorescue@0 107 }
Zerotorescue@0 108 setmetatable(dest, mt)
Zerotorescue@0 109 -- handle already existing tables in the SV
Zerotorescue@0 110 for dk, dv in pairs(dest) do
Zerotorescue@0 111 if not rawget(src, dk) and type(dv) == "table" then
Zerotorescue@0 112 copyDefaults(dv, v)
Zerotorescue@0 113 end
Zerotorescue@0 114 end
Zerotorescue@0 115 else
Zerotorescue@0 116 -- Values are not tables, so this is just a simple return
Zerotorescue@0 117 local mt = {__index = function(t,k) return k~=nil and v or nil end}
Zerotorescue@0 118 setmetatable(dest, mt)
Zerotorescue@0 119 end
Zerotorescue@0 120 elseif type(v) == "table" then
Zerotorescue@0 121 if not rawget(dest, k) then rawset(dest, k, {}) end
Zerotorescue@0 122 if type(dest[k]) == "table" then
Zerotorescue@0 123 copyDefaults(dest[k], v)
Zerotorescue@0 124 if src['**'] then
Zerotorescue@0 125 copyDefaults(dest[k], src['**'])
Zerotorescue@0 126 end
Zerotorescue@0 127 end
Zerotorescue@0 128 else
Zerotorescue@0 129 if rawget(dest, k) == nil then
Zerotorescue@0 130 rawset(dest, k, v)
Zerotorescue@0 131 end
Zerotorescue@0 132 end
Zerotorescue@0 133 end
Zerotorescue@0 134 end
Zerotorescue@0 135
Zerotorescue@0 136 -- Called to remove all defaults in the default table from the database
Zerotorescue@0 137 local function removeDefaults(db, defaults, blocker)
Zerotorescue@0 138 -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
Zerotorescue@0 139 setmetatable(db, nil)
Zerotorescue@0 140 -- loop through the defaults and remove their content
Zerotorescue@0 141 for k,v in pairs(defaults) do
Zerotorescue@0 142 if k == "*" or k == "**" then
Zerotorescue@0 143 if type(v) == "table" then
Zerotorescue@0 144 -- Loop through all the actual k,v pairs and remove
Zerotorescue@0 145 for key, value in pairs(db) do
Zerotorescue@0 146 if type(value) == "table" then
Zerotorescue@0 147 -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
Zerotorescue@0 148 if defaults[key] == nil and (not blocker or blocker[key] == nil) then
Zerotorescue@0 149 removeDefaults(value, v)
Zerotorescue@0 150 -- if the table is empty afterwards, remove it
Zerotorescue@0 151 if next(value) == nil then
Zerotorescue@0 152 db[key] = nil
Zerotorescue@0 153 end
Zerotorescue@0 154 -- if it was specified, only strip ** content, but block values which were set in the key table
Zerotorescue@0 155 elseif k == "**" then
Zerotorescue@0 156 removeDefaults(value, v, defaults[key])
Zerotorescue@0 157 end
Zerotorescue@0 158 end
Zerotorescue@0 159 end
Zerotorescue@0 160 elseif k == "*" then
Zerotorescue@0 161 -- check for non-table default
Zerotorescue@0 162 for key, value in pairs(db) do
Zerotorescue@0 163 if defaults[key] == nil and v == value then
Zerotorescue@0 164 db[key] = nil
Zerotorescue@0 165 end
Zerotorescue@0 166 end
Zerotorescue@0 167 end
Zerotorescue@0 168 elseif type(v) == "table" and type(db[k]) == "table" then
Zerotorescue@0 169 -- if a blocker was set, dive into it, to allow multi-level defaults
Zerotorescue@0 170 removeDefaults(db[k], v, blocker and blocker[k])
Zerotorescue@0 171 if next(db[k]) == nil then
Zerotorescue@0 172 db[k] = nil
Zerotorescue@0 173 end
Zerotorescue@0 174 else
Zerotorescue@0 175 -- check if the current value matches the default, and that its not blocked by another defaults table
Zerotorescue@0 176 if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
Zerotorescue@0 177 db[k] = nil
Zerotorescue@0 178 end
Zerotorescue@0 179 end
Zerotorescue@0 180 end
Zerotorescue@0 181 end
Zerotorescue@0 182
Zerotorescue@0 183 -- This is called when a table section is first accessed, to set up the defaults
Zerotorescue@0 184 local function initSection(db, section, svstore, key, defaults)
Zerotorescue@0 185 local sv = rawget(db, "sv")
Zerotorescue@0 186
Zerotorescue@0 187 local tableCreated
Zerotorescue@0 188 if not sv[svstore] then sv[svstore] = {} end
Zerotorescue@0 189 if not sv[svstore][key] then
Zerotorescue@0 190 sv[svstore][key] = {}
Zerotorescue@0 191 tableCreated = true
Zerotorescue@0 192 end
Zerotorescue@0 193
Zerotorescue@0 194 local tbl = sv[svstore][key]
Zerotorescue@0 195
Zerotorescue@0 196 if defaults then
Zerotorescue@0 197 copyDefaults(tbl, defaults)
Zerotorescue@0 198 end
Zerotorescue@0 199 rawset(db, section, tbl)
Zerotorescue@0 200
Zerotorescue@0 201 return tableCreated, tbl
Zerotorescue@0 202 end
Zerotorescue@0 203
Zerotorescue@0 204 -- Metatable to handle the dynamic creation of sections and copying of sections.
Zerotorescue@0 205 local dbmt = {
Zerotorescue@0 206 __index = function(t, section)
Zerotorescue@0 207 local keys = rawget(t, "keys")
Zerotorescue@0 208 local key = keys[section]
Zerotorescue@0 209 if key then
Zerotorescue@0 210 local defaultTbl = rawget(t, "defaults")
Zerotorescue@0 211 local defaults = defaultTbl and defaultTbl[section]
Zerotorescue@0 212
Zerotorescue@0 213 if section == "profile" then
Zerotorescue@0 214 local new = initSection(t, section, "profiles", key, defaults)
Zerotorescue@0 215 if new then
Zerotorescue@0 216 -- Callback: OnNewProfile, database, newProfileKey
Zerotorescue@0 217 t.callbacks:Fire("OnNewProfile", t, key)
Zerotorescue@0 218 end
Zerotorescue@0 219 elseif section == "profiles" then
Zerotorescue@0 220 local sv = rawget(t, "sv")
Zerotorescue@0 221 if not sv.profiles then sv.profiles = {} end
Zerotorescue@0 222 rawset(t, "profiles", sv.profiles)
Zerotorescue@0 223 elseif section == "global" then
Zerotorescue@0 224 local sv = rawget(t, "sv")
Zerotorescue@0 225 if not sv.global then sv.global = {} end
Zerotorescue@0 226 if defaults then
Zerotorescue@0 227 copyDefaults(sv.global, defaults)
Zerotorescue@0 228 end
Zerotorescue@0 229 rawset(t, section, sv.global)
Zerotorescue@0 230 else
Zerotorescue@0 231 initSection(t, section, section, key, defaults)
Zerotorescue@0 232 end
Zerotorescue@0 233 end
Zerotorescue@0 234
Zerotorescue@0 235 return rawget(t, section)
Zerotorescue@0 236 end
Zerotorescue@0 237 }
Zerotorescue@0 238
Zerotorescue@0 239 local function validateDefaults(defaults, keyTbl, offset)
Zerotorescue@0 240 if not defaults then return end
Zerotorescue@0 241 offset = offset or 0
Zerotorescue@0 242 for k in pairs(defaults) do
Zerotorescue@0 243 if not keyTbl[k] or k == "profiles" then
Zerotorescue@0 244 error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
Zerotorescue@0 245 end
Zerotorescue@0 246 end
Zerotorescue@0 247 end
Zerotorescue@0 248
Zerotorescue@0 249 local preserve_keys = {
Zerotorescue@0 250 ["callbacks"] = true,
Zerotorescue@0 251 ["RegisterCallback"] = true,
Zerotorescue@0 252 ["UnregisterCallback"] = true,
Zerotorescue@0 253 ["UnregisterAllCallbacks"] = true,
Zerotorescue@0 254 ["children"] = true,
Zerotorescue@0 255 }
Zerotorescue@0 256
Zerotorescue@0 257 local realmKey = GetRealmName()
Zerotorescue@0 258 local charKey = UnitName("player") .. " - " .. realmKey
Zerotorescue@0 259 local _, classKey = UnitClass("player")
Zerotorescue@0 260 local _, raceKey = UnitRace("player")
Zerotorescue@0 261 local factionKey = UnitFactionGroup("player")
Zerotorescue@0 262 local factionrealmKey = factionKey .. " - " .. realmKey
Zerotorescue@0 263 -- Actual database initialization function
Zerotorescue@0 264 local function initdb(sv, defaults, defaultProfile, olddb, parent)
Zerotorescue@0 265 -- Generate the database keys for each section
Zerotorescue@0 266
Zerotorescue@0 267 -- map "true" to our "Default" profile
Zerotorescue@0 268 if defaultProfile == true then defaultProfile = "Default" end
Zerotorescue@0 269
Zerotorescue@0 270 local profileKey
Zerotorescue@0 271 if not parent then
Zerotorescue@0 272 -- Make a container for profile keys
Zerotorescue@0 273 if not sv.profileKeys then sv.profileKeys = {} end
Zerotorescue@0 274
Zerotorescue@0 275 -- Try to get the profile selected from the char db
Zerotorescue@0 276 profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
Zerotorescue@0 277
Zerotorescue@0 278 -- save the selected profile for later
Zerotorescue@0 279 sv.profileKeys[charKey] = profileKey
Zerotorescue@0 280 else
Zerotorescue@0 281 -- Use the profile of the parents DB
Zerotorescue@0 282 profileKey = parent.keys.profile or defaultProfile or charKey
Zerotorescue@0 283
Zerotorescue@0 284 -- clear the profileKeys in the DB, namespaces don't need to store them
Zerotorescue@0 285 sv.profileKeys = nil
Zerotorescue@0 286 end
Zerotorescue@0 287
Zerotorescue@0 288 -- This table contains keys that enable the dynamic creation
Zerotorescue@0 289 -- of each section of the table. The 'global' and 'profiles'
Zerotorescue@0 290 -- have a key of true, since they are handled in a special case
Zerotorescue@0 291 local keyTbl= {
Zerotorescue@0 292 ["char"] = charKey,
Zerotorescue@0 293 ["realm"] = realmKey,
Zerotorescue@0 294 ["class"] = classKey,
Zerotorescue@0 295 ["race"] = raceKey,
Zerotorescue@0 296 ["faction"] = factionKey,
Zerotorescue@0 297 ["factionrealm"] = factionrealmKey,
Zerotorescue@0 298 ["profile"] = profileKey,
Zerotorescue@0 299 ["global"] = true,
Zerotorescue@0 300 ["profiles"] = true,
Zerotorescue@0 301 }
Zerotorescue@0 302
Zerotorescue@0 303 validateDefaults(defaults, keyTbl, 1)
Zerotorescue@0 304
Zerotorescue@0 305 -- This allows us to use this function to reset an entire database
Zerotorescue@0 306 -- Clear out the old database
Zerotorescue@0 307 if olddb then
Zerotorescue@0 308 for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
Zerotorescue@0 309 end
Zerotorescue@0 310
Zerotorescue@0 311 -- Give this database the metatable so it initializes dynamically
Zerotorescue@0 312 local db = setmetatable(olddb or {}, dbmt)
Zerotorescue@0 313
Zerotorescue@0 314 if not rawget(db, "callbacks") then
Zerotorescue@0 315 -- try to load CallbackHandler-1.0 if it loaded after our library
Zerotorescue@0 316 if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
Zerotorescue@0 317 db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
Zerotorescue@0 318 end
Zerotorescue@0 319
Zerotorescue@0 320 -- Copy methods locally into the database object, to avoid hitting
Zerotorescue@0 321 -- the metatable when calling methods
Zerotorescue@0 322
Zerotorescue@0 323 if not parent then
Zerotorescue@0 324 for name, func in pairs(DBObjectLib) do
Zerotorescue@0 325 db[name] = func
Zerotorescue@0 326 end
Zerotorescue@0 327 else
Zerotorescue@0 328 -- hack this one in
Zerotorescue@0 329 db.RegisterDefaults = DBObjectLib.RegisterDefaults
Zerotorescue@0 330 db.ResetProfile = DBObjectLib.ResetProfile
Zerotorescue@0 331 end
Zerotorescue@0 332
Zerotorescue@0 333 -- Set some properties in the database object
Zerotorescue@0 334 db.profiles = sv.profiles
Zerotorescue@0 335 db.keys = keyTbl
Zerotorescue@0 336 db.sv = sv
Zerotorescue@0 337 --db.sv_name = name
Zerotorescue@0 338 db.defaults = defaults
Zerotorescue@0 339 db.parent = parent
Zerotorescue@0 340
Zerotorescue@0 341 -- store the DB in the registry
Zerotorescue@0 342 AceDB.db_registry[db] = true
Zerotorescue@0 343
Zerotorescue@0 344 return db
Zerotorescue@0 345 end
Zerotorescue@0 346
Zerotorescue@0 347 -- handle PLAYER_LOGOUT
Zerotorescue@0 348 -- strip all defaults from all databases
Zerotorescue@0 349 -- and cleans up empty sections
Zerotorescue@0 350 local function logoutHandler(frame, event)
Zerotorescue@0 351 if event == "PLAYER_LOGOUT" then
Zerotorescue@0 352 for db in pairs(AceDB.db_registry) do
Zerotorescue@0 353 db.callbacks:Fire("OnDatabaseShutdown", db)
Zerotorescue@0 354 db:RegisterDefaults(nil)
Zerotorescue@0 355
Zerotorescue@0 356 -- cleanup sections that are empty without defaults
Zerotorescue@0 357 local sv = rawget(db, "sv")
Zerotorescue@0 358 for section in pairs(db.keys) do
Zerotorescue@0 359 if rawget(sv, section) then
Zerotorescue@0 360 -- global is special, all other sections have sub-entrys
Zerotorescue@0 361 -- also don't delete empty profiles on main dbs, only on namespaces
Zerotorescue@0 362 if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
Zerotorescue@0 363 for key in pairs(sv[section]) do
Zerotorescue@0 364 if not next(sv[section][key]) then
Zerotorescue@0 365 sv[section][key] = nil
Zerotorescue@0 366 end
Zerotorescue@0 367 end
Zerotorescue@0 368 end
Zerotorescue@0 369 if not next(sv[section]) then
Zerotorescue@0 370 sv[section] = nil
Zerotorescue@0 371 end
Zerotorescue@0 372 end
Zerotorescue@0 373 end
Zerotorescue@0 374 end
Zerotorescue@0 375 end
Zerotorescue@0 376 end
Zerotorescue@0 377
Zerotorescue@0 378 AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
Zerotorescue@0 379 AceDB.frame:SetScript("OnEvent", logoutHandler)
Zerotorescue@0 380
Zerotorescue@0 381
Zerotorescue@0 382 --[[-------------------------------------------------------------------------
Zerotorescue@0 383 AceDB Object Method Definitions
Zerotorescue@0 384 ---------------------------------------------------------------------------]]
Zerotorescue@0 385
Zerotorescue@0 386 --- Sets the defaults table for the given database object by clearing any
Zerotorescue@0 387 -- that are currently set, and then setting the new defaults.
Zerotorescue@0 388 -- @param defaults A table of defaults for this database
Zerotorescue@0 389 function DBObjectLib:RegisterDefaults(defaults)
Zerotorescue@0 390 if defaults and type(defaults) ~= "table" then
Zerotorescue@0 391 error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 2)
Zerotorescue@0 392 end
Zerotorescue@0 393
Zerotorescue@0 394 validateDefaults(defaults, self.keys)
Zerotorescue@0 395
Zerotorescue@0 396 -- Remove any currently set defaults
Zerotorescue@0 397 if self.defaults then
Zerotorescue@0 398 for section,key in pairs(self.keys) do
Zerotorescue@0 399 if self.defaults[section] and rawget(self, section) then
Zerotorescue@0 400 removeDefaults(self[section], self.defaults[section])
Zerotorescue@0 401 end
Zerotorescue@0 402 end
Zerotorescue@0 403 end
Zerotorescue@0 404
Zerotorescue@0 405 -- Set the DBObject.defaults table
Zerotorescue@0 406 self.defaults = defaults
Zerotorescue@0 407
Zerotorescue@0 408 -- Copy in any defaults, only touching those sections already created
Zerotorescue@0 409 if defaults then
Zerotorescue@0 410 for section,key in pairs(self.keys) do
Zerotorescue@0 411 if defaults[section] and rawget(self, section) then
Zerotorescue@0 412 copyDefaults(self[section], defaults[section])
Zerotorescue@0 413 end
Zerotorescue@0 414 end
Zerotorescue@0 415 end
Zerotorescue@0 416 end
Zerotorescue@0 417
Zerotorescue@0 418 --- Changes the profile of the database and all of it's namespaces to the
Zerotorescue@0 419 -- supplied named profile
Zerotorescue@0 420 -- @param name The name of the profile to set as the current profile
Zerotorescue@0 421 function DBObjectLib:SetProfile(name)
Zerotorescue@0 422 if type(name) ~= "string" then
Zerotorescue@0 423 error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 2)
Zerotorescue@0 424 end
Zerotorescue@0 425
Zerotorescue@0 426 -- changing to the same profile, dont do anything
Zerotorescue@0 427 if name == self.keys.profile then return end
Zerotorescue@0 428
Zerotorescue@0 429 local oldProfile = self.profile
Zerotorescue@0 430 local defaults = self.defaults and self.defaults.profile
Zerotorescue@0 431
Zerotorescue@0 432 -- Callback: OnProfileShutdown, database
Zerotorescue@0 433 self.callbacks:Fire("OnProfileShutdown", self)
Zerotorescue@0 434
Zerotorescue@0 435 if oldProfile and defaults then
Zerotorescue@0 436 -- Remove the defaults from the old profile
Zerotorescue@0 437 removeDefaults(oldProfile, defaults)
Zerotorescue@0 438 end
Zerotorescue@0 439
Zerotorescue@0 440 self.profile = nil
Zerotorescue@0 441 self.keys["profile"] = name
Zerotorescue@0 442
Zerotorescue@0 443 -- if the storage exists, save the new profile
Zerotorescue@0 444 -- this won't exist on namespaces.
Zerotorescue@0 445 if self.sv.profileKeys then
Zerotorescue@0 446 self.sv.profileKeys[charKey] = name
Zerotorescue@0 447 end
Zerotorescue@0 448
Zerotorescue@0 449 -- populate to child namespaces
Zerotorescue@0 450 if self.children then
Zerotorescue@0 451 for _, db in pairs(self.children) do
Zerotorescue@0 452 DBObjectLib.SetProfile(db, name)
Zerotorescue@0 453 end
Zerotorescue@0 454 end
Zerotorescue@0 455
Zerotorescue@0 456 -- Callback: OnProfileChanged, database, newProfileKey
Zerotorescue@0 457 self.callbacks:Fire("OnProfileChanged", self, name)
Zerotorescue@0 458 end
Zerotorescue@0 459
Zerotorescue@0 460 --- Returns a table with the names of the existing profiles in the database.
Zerotorescue@0 461 -- You can optionally supply a table to re-use for this purpose.
Zerotorescue@0 462 -- @param tbl A table to store the profile names in (optional)
Zerotorescue@0 463 function DBObjectLib:GetProfiles(tbl)
Zerotorescue@0 464 if tbl and type(tbl) ~= "table" then
Zerotorescue@0 465 error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 2)
Zerotorescue@0 466 end
Zerotorescue@0 467
Zerotorescue@0 468 -- Clear the container table
Zerotorescue@0 469 if tbl then
Zerotorescue@0 470 for k,v in pairs(tbl) do tbl[k] = nil end
Zerotorescue@0 471 else
Zerotorescue@0 472 tbl = {}
Zerotorescue@0 473 end
Zerotorescue@0 474
Zerotorescue@0 475 local curProfile = self.keys.profile
Zerotorescue@0 476
Zerotorescue@0 477 local i = 0
Zerotorescue@0 478 for profileKey in pairs(self.profiles) do
Zerotorescue@0 479 i = i + 1
Zerotorescue@0 480 tbl[i] = profileKey
Zerotorescue@0 481 if curProfile and profileKey == curProfile then curProfile = nil end
Zerotorescue@0 482 end
Zerotorescue@0 483
Zerotorescue@0 484 -- Add the current profile, if it hasn't been created yet
Zerotorescue@0 485 if curProfile then
Zerotorescue@0 486 i = i + 1
Zerotorescue@0 487 tbl[i] = curProfile
Zerotorescue@0 488 end
Zerotorescue@0 489
Zerotorescue@0 490 return tbl, i
Zerotorescue@0 491 end
Zerotorescue@0 492
Zerotorescue@0 493 --- Returns the current profile name used by the database
Zerotorescue@0 494 function DBObjectLib:GetCurrentProfile()
Zerotorescue@0 495 return self.keys.profile
Zerotorescue@0 496 end
Zerotorescue@0 497
Zerotorescue@0 498 --- Deletes a named profile. This profile must not be the active profile.
Zerotorescue@0 499 -- @param name The name of the profile to be deleted
Zerotorescue@0 500 -- @param silent If true, do not raise an error when the profile does not exist
Zerotorescue@0 501 function DBObjectLib:DeleteProfile(name, silent)
Zerotorescue@0 502 if type(name) ~= "string" then
Zerotorescue@0 503 error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2)
Zerotorescue@0 504 end
Zerotorescue@0 505
Zerotorescue@0 506 if self.keys.profile == name then
Zerotorescue@0 507 error("Cannot delete the active profile in an AceDBObject.", 2)
Zerotorescue@0 508 end
Zerotorescue@0 509
Zerotorescue@0 510 if not rawget(self.profiles, name) and not silent then
Zerotorescue@0 511 error("Cannot delete profile '" .. name .. "'. It does not exist.", 2)
Zerotorescue@0 512 end
Zerotorescue@0 513
Zerotorescue@0 514 self.profiles[name] = nil
Zerotorescue@0 515
Zerotorescue@0 516 -- populate to child namespaces
Zerotorescue@0 517 if self.children then
Zerotorescue@0 518 for _, db in pairs(self.children) do
Zerotorescue@0 519 DBObjectLib.DeleteProfile(db, name, true)
Zerotorescue@0 520 end
Zerotorescue@0 521 end
Zerotorescue@0 522
Zerotorescue@0 523 -- Callback: OnProfileDeleted, database, profileKey
Zerotorescue@0 524 self.callbacks:Fire("OnProfileDeleted", self, name)
Zerotorescue@0 525 end
Zerotorescue@0 526
Zerotorescue@0 527 --- Copies a named profile into the current profile, overwriting any conflicting
Zerotorescue@0 528 -- settings.
Zerotorescue@0 529 -- @param name The name of the profile to be copied into the current profile
Zerotorescue@0 530 -- @param silent If true, do not raise an error when the profile does not exist
Zerotorescue@0 531 function DBObjectLib:CopyProfile(name, silent)
Zerotorescue@0 532 if type(name) ~= "string" then
Zerotorescue@0 533 error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2)
Zerotorescue@0 534 end
Zerotorescue@0 535
Zerotorescue@0 536 if name == self.keys.profile then
Zerotorescue@0 537 error("Cannot have the same source and destination profiles.", 2)
Zerotorescue@0 538 end
Zerotorescue@0 539
Zerotorescue@0 540 if not rawget(self.profiles, name) and not silent then
Zerotorescue@0 541 error("Cannot copy profile '" .. name .. "'. It does not exist.", 2)
Zerotorescue@0 542 end
Zerotorescue@0 543
Zerotorescue@0 544 -- Reset the profile before copying
Zerotorescue@0 545 DBObjectLib.ResetProfile(self, nil, true)
Zerotorescue@0 546
Zerotorescue@0 547 local profile = self.profile
Zerotorescue@0 548 local source = self.profiles[name]
Zerotorescue@0 549
Zerotorescue@0 550 copyTable(source, profile)
Zerotorescue@0 551
Zerotorescue@0 552 -- populate to child namespaces
Zerotorescue@0 553 if self.children then
Zerotorescue@0 554 for _, db in pairs(self.children) do
Zerotorescue@0 555 DBObjectLib.CopyProfile(db, name, true)
Zerotorescue@0 556 end
Zerotorescue@0 557 end
Zerotorescue@0 558
Zerotorescue@0 559 -- Callback: OnProfileCopied, database, sourceProfileKey
Zerotorescue@0 560 self.callbacks:Fire("OnProfileCopied", self, name)
Zerotorescue@0 561 end
Zerotorescue@0 562
Zerotorescue@0 563 --- Resets the current profile to the default values (if specified).
Zerotorescue@0 564 -- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
Zerotorescue@0 565 -- @param noCallbacks if set to true, won't fire the OnProfileReset callback
Zerotorescue@0 566 function DBObjectLib:ResetProfile(noChildren, noCallbacks)
Zerotorescue@0 567 local profile = self.profile
Zerotorescue@0 568
Zerotorescue@0 569 for k,v in pairs(profile) do
Zerotorescue@0 570 profile[k] = nil
Zerotorescue@0 571 end
Zerotorescue@0 572
Zerotorescue@0 573 local defaults = self.defaults and self.defaults.profile
Zerotorescue@0 574 if defaults then
Zerotorescue@0 575 copyDefaults(profile, defaults)
Zerotorescue@0 576 end
Zerotorescue@0 577
Zerotorescue@0 578 -- populate to child namespaces
Zerotorescue@0 579 if self.children and not noChildren then
Zerotorescue@0 580 for _, db in pairs(self.children) do
Zerotorescue@0 581 DBObjectLib.ResetProfile(db, nil, noCallbacks)
Zerotorescue@0 582 end
Zerotorescue@0 583 end
Zerotorescue@0 584
Zerotorescue@0 585 -- Callback: OnProfileReset, database
Zerotorescue@0 586 if not noCallbacks then
Zerotorescue@0 587 self.callbacks:Fire("OnProfileReset", self)
Zerotorescue@0 588 end
Zerotorescue@0 589 end
Zerotorescue@0 590
Zerotorescue@0 591 --- Resets the entire database, using the string defaultProfile as the new default
Zerotorescue@0 592 -- profile.
Zerotorescue@0 593 -- @param defaultProfile The profile name to use as the default
Zerotorescue@0 594 function DBObjectLib:ResetDB(defaultProfile)
Zerotorescue@0 595 if defaultProfile and type(defaultProfile) ~= "string" then
Zerotorescue@0 596 error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2)
Zerotorescue@0 597 end
Zerotorescue@0 598
Zerotorescue@0 599 local sv = self.sv
Zerotorescue@0 600 for k,v in pairs(sv) do
Zerotorescue@0 601 sv[k] = nil
Zerotorescue@0 602 end
Zerotorescue@0 603
Zerotorescue@0 604 local parent = self.parent
Zerotorescue@0 605
Zerotorescue@0 606 initdb(sv, self.defaults, defaultProfile, self)
Zerotorescue@0 607
Zerotorescue@0 608 -- fix the child namespaces
Zerotorescue@0 609 if self.children then
Zerotorescue@0 610 if not sv.namespaces then sv.namespaces = {} end
Zerotorescue@0 611 for name, db in pairs(self.children) do
Zerotorescue@0 612 if not sv.namespaces[name] then sv.namespaces[name] = {} end
Zerotorescue@0 613 initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
Zerotorescue@0 614 end
Zerotorescue@0 615 end
Zerotorescue@0 616
Zerotorescue@0 617 -- Callback: OnDatabaseReset, database
Zerotorescue@0 618 self.callbacks:Fire("OnDatabaseReset", self)
Zerotorescue@0 619 -- Callback: OnProfileChanged, database, profileKey
Zerotorescue@0 620 self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
Zerotorescue@0 621
Zerotorescue@0 622 return self
Zerotorescue@0 623 end
Zerotorescue@0 624
Zerotorescue@0 625 --- Creates a new database namespace, directly tied to the database. This
Zerotorescue@0 626 -- is a full scale database in it's own rights other than the fact that
Zerotorescue@0 627 -- it cannot control its profile individually
Zerotorescue@0 628 -- @param name The name of the new namespace
Zerotorescue@0 629 -- @param defaults A table of values to use as defaults
Zerotorescue@0 630 function DBObjectLib:RegisterNamespace(name, defaults)
Zerotorescue@0 631 if type(name) ~= "string" then
Zerotorescue@0 632 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2)
Zerotorescue@0 633 end
Zerotorescue@0 634 if defaults and type(defaults) ~= "table" then
Zerotorescue@0 635 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2)
Zerotorescue@0 636 end
Zerotorescue@0 637 if self.children and self.children[name] then
Zerotorescue@0 638 error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 2)
Zerotorescue@0 639 end
Zerotorescue@0 640
Zerotorescue@0 641 local sv = self.sv
Zerotorescue@0 642 if not sv.namespaces then sv.namespaces = {} end
Zerotorescue@0 643 if not sv.namespaces[name] then
Zerotorescue@0 644 sv.namespaces[name] = {}
Zerotorescue@0 645 end
Zerotorescue@0 646
Zerotorescue@0 647 local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
Zerotorescue@0 648
Zerotorescue@0 649 if not self.children then self.children = {} end
Zerotorescue@0 650 self.children[name] = newDB
Zerotorescue@0 651 return newDB
Zerotorescue@0 652 end
Zerotorescue@0 653
Zerotorescue@0 654 --- Returns an already existing namespace from the database object.
Zerotorescue@0 655 -- @param name The name of the new namespace
Zerotorescue@0 656 -- @param silent if true, the addon is optional, silently return nil if its not found
Zerotorescue@0 657 -- @usage
Zerotorescue@0 658 -- local namespace = self.db:GetNamespace('namespace')
Zerotorescue@0 659 -- @return the namespace object if found
Zerotorescue@0 660 function DBObjectLib:GetNamespace(name, silent)
Zerotorescue@0 661 if type(name) ~= "string" then
Zerotorescue@0 662 error("Usage: AceDBObject:GetNamespace(name): 'name' - string expected.", 2)
Zerotorescue@0 663 end
Zerotorescue@0 664 if not silent and not (self.children and self.children[name]) then
Zerotorescue@0 665 error ("Usage: AceDBObject:GetNamespace(name): 'name' - namespace does not exist.", 2)
Zerotorescue@0 666 end
Zerotorescue@0 667 if not self.children then self.children = {} end
Zerotorescue@0 668 return self.children[name]
Zerotorescue@0 669 end
Zerotorescue@0 670
Zerotorescue@0 671 --[[-------------------------------------------------------------------------
Zerotorescue@0 672 AceDB Exposed Methods
Zerotorescue@0 673 ---------------------------------------------------------------------------]]
Zerotorescue@0 674
Zerotorescue@0 675 --- Creates a new database object that can be used to handle database settings and profiles.
Zerotorescue@0 676 -- By default, an empty DB is created, using a character specific profile.
Zerotorescue@0 677 --
Zerotorescue@0 678 -- You can override the default profile used by passing any profile name as the third argument,
Zerotorescue@0 679 -- or by passing //true// as the third argument to use a globally shared profile called "Default".
Zerotorescue@0 680 --
Zerotorescue@0 681 -- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
Zerotorescue@0 682 -- will use a profile named "char", and not a character-specific profile.
Zerotorescue@0 683 -- @param tbl The name of variable, or table to use for the database
Zerotorescue@0 684 -- @param defaults A table of database defaults
Zerotorescue@0 685 -- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
Zerotorescue@0 686 -- You can also pass //true// to use a shared global profile called "Default".
Zerotorescue@0 687 -- @usage
Zerotorescue@0 688 -- -- Create an empty DB using a character-specific default profile.
Zerotorescue@0 689 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
Zerotorescue@0 690 -- @usage
Zerotorescue@0 691 -- -- Create a DB using defaults and using a shared default profile
Zerotorescue@0 692 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
Zerotorescue@0 693 function AceDB:New(tbl, defaults, defaultProfile)
Zerotorescue@0 694 if type(tbl) == "string" then
Zerotorescue@0 695 local name = tbl
Zerotorescue@0 696 tbl = _G[name]
Zerotorescue@0 697 if not tbl then
Zerotorescue@0 698 tbl = {}
Zerotorescue@0 699 _G[name] = tbl
Zerotorescue@0 700 end
Zerotorescue@0 701 end
Zerotorescue@0 702
Zerotorescue@0 703 if type(tbl) ~= "table" then
Zerotorescue@0 704 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2)
Zerotorescue@0 705 end
Zerotorescue@0 706
Zerotorescue@0 707 if defaults and type(defaults) ~= "table" then
Zerotorescue@0 708 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2)
Zerotorescue@0 709 end
Zerotorescue@0 710
Zerotorescue@0 711 if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
Zerotorescue@0 712 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected.", 2)
Zerotorescue@0 713 end
Zerotorescue@0 714
Zerotorescue@0 715 return initdb(tbl, defaults, defaultProfile)
Zerotorescue@0 716 end
Zerotorescue@0 717
Zerotorescue@0 718 -- upgrade existing databases
Zerotorescue@0 719 for db in pairs(AceDB.db_registry) do
Zerotorescue@0 720 if not db.parent then
Zerotorescue@0 721 for name,func in pairs(DBObjectLib) do
Zerotorescue@0 722 db[name] = func
Zerotorescue@0 723 end
Zerotorescue@0 724 else
Zerotorescue@0 725 db.RegisterDefaults = DBObjectLib.RegisterDefaults
Zerotorescue@0 726 db.ResetProfile = DBObjectLib.ResetProfile
Zerotorescue@0 727 end
Zerotorescue@0 728 end