annotate Libs/AceDB-3.0/AceDB-3.0.lua @ 58:0682d738499b v8.0.1.058

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