1 --- **AceDB-3.0** manages the SavedVariables of your addon.
2 -- It offers profile management, smart defaults and namespaces for modules.\\
3 -- Data can be saved in different data-types, depending on its intended usage.
4 -- The most common data-type is the `profile` type, which allows the user to choose
5 -- the active profile, and manage the profiles of all of his characters.\\
6 -- The following data types are available:
7 -- * **char** Character-specific data. Every character has its own database.
8 -- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
9 -- * **class** Class-specific data. All of the players characters of the same class share this database.
10 -- * **race** Race-specific data. All of the players characters of the same race share this database.
11 -- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
12 -- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
13 -- * **locale** Locale specific data, based on the locale of the players game client.
14 -- * **global** Global Data. All characters on the same account share this database.
15 -- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
17 -- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
18 -- of the DBObjectLib listed here. \\
19 -- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
20 -- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
21 -- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
23 -- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
25 -- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
28 -- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
30 -- -- declare defaults to be used in the DB
37 -- function MyAddon:OnInitialize()
38 -- -- Assuming the .toc says ## SavedVariables: MyAddonDB
39 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
42 -- @name AceDB-3.0.lua
43 -- @release $Id: AceDB-3.0.lua 1142 2016-07-11 08:36:19Z nevcairiel $
44 local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 26
45 local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
47 if not AceDB then return end -- No upgrade needed
50 local type, pairs, next, error = type, pairs, next, error
51 local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
56 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
57 -- List them here for Mikk's FindGlobals script
60 AceDB.db_registry = AceDB.db_registry or {}
61 AceDB.frame = AceDB.frame or CreateFrame("Frame")
64 local CallbackDummy = { Fire = function() end }
66 local DBObjectLib = {}
68 --[[-------------------------------------------------------------------------
69 AceDB Utility Functions
70 ---------------------------------------------------------------------------]]
72 -- Simple shallow copy for copying defaults
73 local function copyTable(src, dest)
74 if type(dest) ~= "table" then dest = {} end
75 if type(src) == "table" then
76 for k,v in pairs(src) do
77 if type(v) == "table" then
78 -- try to index the key first so that the metatable creates the defaults, if set, and use that table
79 v = copyTable(v, dest[k])
87 -- Called to add defaults to a section of the database
89 -- When a ["*"] default section is indexed with a new key, a table is returned
90 -- and set in the host table. These tables must be cleaned up by removeDefaults
91 -- in order to ensure we don't write empty default tables.
92 local function copyDefaults(dest, src)
93 -- this happens if some value in the SV overwrites our default value with a non-table
94 --if type(dest) ~= "table" then return end
95 for k, v in pairs(src) do
96 if k == "*" or k == "**" then
97 if type(v) == "table" then
98 -- This is a metatable used for table defaults
100 -- This handles the lookup and creation of new subtables
101 __index = function(t,k)
102 if k == nil then return nil end
109 setmetatable(dest, mt)
110 -- handle already existing tables in the SV
111 for dk, dv in pairs(dest) do
112 if not rawget(src, dk) and type(dv) == "table" then
117 -- Values are not tables, so this is just a simple return
118 local mt = {__index = function(t,k) return k~=nil and v or nil end}
119 setmetatable(dest, mt)
121 elseif type(v) == "table" then
122 if not rawget(dest, k) then rawset(dest, k, {}) end
123 if type(dest[k]) == "table" then
124 copyDefaults(dest[k], v)
126 copyDefaults(dest[k], src['**'])
130 if rawget(dest, k) == nil then
137 -- Called to remove all defaults in the default table from the database
138 local function removeDefaults(db, defaults, blocker)
139 -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
140 setmetatable(db, nil)
141 -- loop through the defaults and remove their content
142 for k,v in pairs(defaults) do
143 if k == "*" or k == "**" then
144 if type(v) == "table" then
145 -- Loop through all the actual k,v pairs and remove
146 for key, value in pairs(db) do
147 if type(value) == "table" then
148 -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
149 if defaults[key] == nil and (not blocker or blocker[key] == nil) then
150 removeDefaults(value, v)
151 -- if the table is empty afterwards, remove it
152 if next(value) == nil then
155 -- if it was specified, only strip ** content, but block values which were set in the key table
156 elseif k == "**" then
157 removeDefaults(value, v, defaults[key])
162 -- check for non-table default
163 for key, value in pairs(db) do
164 if defaults[key] == nil and v == value then
169 elseif type(v) == "table" and type(db[k]) == "table" then
170 -- if a blocker was set, dive into it, to allow multi-level defaults
171 removeDefaults(db[k], v, blocker and blocker[k])
172 if next(db[k]) == nil then
176 -- check if the current value matches the default, and that its not blocked by another defaults table
177 if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
184 -- This is called when a table section is first accessed, to set up the defaults
185 local function initSection(db, section, svstore, key, defaults)
186 local sv = rawget(db, "sv")
189 if not sv[svstore] then sv[svstore] = {} end
190 if not sv[svstore][key] then
191 sv[svstore][key] = {}
195 local tbl = sv[svstore][key]
198 copyDefaults(tbl, defaults)
200 rawset(db, section, tbl)
202 return tableCreated, tbl
205 -- Metatable to handle the dynamic creation of sections and copying of sections.
207 __index = function(t, section)
208 local keys = rawget(t, "keys")
209 local key = keys[section]
211 local defaultTbl = rawget(t, "defaults")
212 local defaults = defaultTbl and defaultTbl[section]
214 if section == "profile" then
215 local new = initSection(t, section, "profiles", key, defaults)
217 -- Callback: OnNewProfile, database, newProfileKey
218 t.callbacks:Fire("OnNewProfile", t, key)
220 elseif section == "profiles" then
221 local sv = rawget(t, "sv")
222 if not sv.profiles then sv.profiles = {} end
223 rawset(t, "profiles", sv.profiles)
224 elseif section == "global" then
225 local sv = rawget(t, "sv")
226 if not sv.global then sv.global = {} end
228 copyDefaults(sv.global, defaults)
230 rawset(t, section, sv.global)
232 initSection(t, section, section, key, defaults)
236 return rawget(t, section)
240 local function validateDefaults(defaults, keyTbl, offset)
241 if not defaults then return end
243 for k in pairs(defaults) do
244 if not keyTbl[k] or k == "profiles" then
245 error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
250 local preserve_keys = {
251 ["callbacks"] = true,
252 ["RegisterCallback"] = true,
253 ["UnregisterCallback"] = true,
254 ["UnregisterAllCallbacks"] = true,
258 local realmKey = GetRealmName()
259 local charKey = UnitName("player") .. " - " .. realmKey
260 local _, classKey = UnitClass("player")
261 local _, raceKey = UnitRace("player")
262 local factionKey = UnitFactionGroup("player")
263 local factionrealmKey = factionKey .. " - " .. realmKey
264 local localeKey = GetLocale():lower()
266 local regionTable = { "US", "KR", "EU", "TW", "CN" }
267 local regionKey = regionTable[GetCurrentRegion()]
268 local factionrealmregionKey = factionrealmKey .. " - " .. regionKey
270 -- Actual database initialization function
271 local function initdb(sv, defaults, defaultProfile, olddb, parent)
272 -- Generate the database keys for each section
274 -- map "true" to our "Default" profile
275 if defaultProfile == true then defaultProfile = "Default" end
279 -- Make a container for profile keys
280 if not sv.profileKeys then sv.profileKeys = {} end
282 -- Try to get the profile selected from the char db
283 profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
285 -- save the selected profile for later
286 sv.profileKeys[charKey] = profileKey
288 -- Use the profile of the parents DB
289 profileKey = parent.keys.profile or defaultProfile or charKey
291 -- clear the profileKeys in the DB, namespaces don't need to store them
295 -- This table contains keys that enable the dynamic creation
296 -- of each section of the table. The 'global' and 'profiles'
297 -- have a key of true, since they are handled in a special case
300 ["realm"] = realmKey,
301 ["class"] = classKey,
303 ["faction"] = factionKey,
304 ["factionrealm"] = factionrealmKey,
305 ["factionrealmregion"] = factionrealmregionKey,
306 ["profile"] = profileKey,
307 ["locale"] = localeKey,
312 validateDefaults(defaults, keyTbl, 1)
314 -- This allows us to use this function to reset an entire database
315 -- Clear out the old database
317 for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
320 -- Give this database the metatable so it initializes dynamically
321 local db = setmetatable(olddb or {}, dbmt)
323 if not rawget(db, "callbacks") then
324 -- try to load CallbackHandler-1.0 if it loaded after our library
325 if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
326 db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
329 -- Copy methods locally into the database object, to avoid hitting
330 -- the metatable when calling methods
333 for name, func in pairs(DBObjectLib) do
338 db.RegisterDefaults = DBObjectLib.RegisterDefaults
339 db.ResetProfile = DBObjectLib.ResetProfile
342 -- Set some properties in the database object
343 db.profiles = sv.profiles
347 db.defaults = defaults
350 -- store the DB in the registry
351 AceDB.db_registry[db] = true
356 -- handle PLAYER_LOGOUT
357 -- strip all defaults from all databases
358 -- and cleans up empty sections
359 local function logoutHandler(frame, event)
360 if event == "PLAYER_LOGOUT" then
361 for db in pairs(AceDB.db_registry) do
362 db.callbacks:Fire("OnDatabaseShutdown", db)
363 db:RegisterDefaults(nil)
365 -- cleanup sections that are empty without defaults
366 local sv = rawget(db, "sv")
367 for section in pairs(db.keys) do
368 if rawget(sv, section) then
369 -- global is special, all other sections have sub-entrys
370 -- also don't delete empty profiles on main dbs, only on namespaces
371 if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
372 for key in pairs(sv[section]) do
373 if not next(sv[section][key]) then
374 sv[section][key] = nil
378 if not next(sv[section]) then
387 AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
388 AceDB.frame:SetScript("OnEvent", logoutHandler)
391 --[[-------------------------------------------------------------------------
392 AceDB Object Method Definitions
393 ---------------------------------------------------------------------------]]
395 --- Sets the defaults table for the given database object by clearing any
396 -- that are currently set, and then setting the new defaults.
397 -- @param defaults A table of defaults for this database
398 function DBObjectLib:RegisterDefaults(defaults)
399 if defaults and type(defaults) ~= "table" then
400 error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 2)
403 validateDefaults(defaults, self.keys)
405 -- Remove any currently set defaults
406 if self.defaults then
407 for section,key in pairs(self.keys) do
408 if self.defaults[section] and rawget(self, section) then
409 removeDefaults(self[section], self.defaults[section])
414 -- Set the DBObject.defaults table
415 self.defaults = defaults
417 -- Copy in any defaults, only touching those sections already created
419 for section,key in pairs(self.keys) do
420 if defaults[section] and rawget(self, section) then
421 copyDefaults(self[section], defaults[section])
427 --- Changes the profile of the database and all of it's namespaces to the
428 -- supplied named profile
429 -- @param name The name of the profile to set as the current profile
430 function DBObjectLib:SetProfile(name)
431 if type(name) ~= "string" then
432 error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 2)
435 -- changing to the same profile, dont do anything
436 if name == self.keys.profile then return end
438 local oldProfile = self.profile
439 local defaults = self.defaults and self.defaults.profile
441 -- Callback: OnProfileShutdown, database
442 self.callbacks:Fire("OnProfileShutdown", self)
444 if oldProfile and defaults then
445 -- Remove the defaults from the old profile
446 removeDefaults(oldProfile, defaults)
450 self.keys["profile"] = name
452 -- if the storage exists, save the new profile
453 -- this won't exist on namespaces.
454 if self.sv.profileKeys then
455 self.sv.profileKeys[charKey] = name
458 -- populate to child namespaces
459 if self.children then
460 for _, db in pairs(self.children) do
461 DBObjectLib.SetProfile(db, name)
465 -- Callback: OnProfileChanged, database, newProfileKey
466 self.callbacks:Fire("OnProfileChanged", self, name)
469 --- Returns a table with the names of the existing profiles in the database.
470 -- You can optionally supply a table to re-use for this purpose.
471 -- @param tbl A table to store the profile names in (optional)
472 function DBObjectLib:GetProfiles(tbl)
473 if tbl and type(tbl) ~= "table" then
474 error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 2)
477 -- Clear the container table
479 for k,v in pairs(tbl) do tbl[k] = nil end
484 local curProfile = self.keys.profile
487 for profileKey in pairs(self.profiles) do
490 if curProfile and profileKey == curProfile then curProfile = nil end
493 -- Add the current profile, if it hasn't been created yet
502 --- Returns the current profile name used by the database
503 function DBObjectLib:GetCurrentProfile()
504 return self.keys.profile
507 --- Deletes a named profile. This profile must not be the active profile.
508 -- @param name The name of the profile to be deleted
509 -- @param silent If true, do not raise an error when the profile does not exist
510 function DBObjectLib:DeleteProfile(name, silent)
511 if type(name) ~= "string" then
512 error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2)
515 if self.keys.profile == name then
516 error("Cannot delete the active profile in an AceDBObject.", 2)
519 if not rawget(self.profiles, name) and not silent then
520 error("Cannot delete profile '" .. name .. "'. It does not exist.", 2)
523 self.profiles[name] = nil
525 -- populate to child namespaces
526 if self.children then
527 for _, db in pairs(self.children) do
528 DBObjectLib.DeleteProfile(db, name, true)
532 -- switch all characters that use this profile back to the default
533 if self.sv.profileKeys then
534 for key, profile in pairs(self.sv.profileKeys) do
535 if profile == name then
536 self.sv.profileKeys[key] = nil
541 -- Callback: OnProfileDeleted, database, profileKey
542 self.callbacks:Fire("OnProfileDeleted", self, name)
545 --- Copies a named profile into the current profile, overwriting any conflicting
547 -- @param name The name of the profile to be copied into the current profile
548 -- @param silent If true, do not raise an error when the profile does not exist
549 function DBObjectLib:CopyProfile(name, silent)
550 if type(name) ~= "string" then
551 error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2)
554 if name == self.keys.profile then
555 error("Cannot have the same source and destination profiles.", 2)
558 if not rawget(self.profiles, name) and not silent then
559 error("Cannot copy profile '" .. name .. "'. It does not exist.", 2)
562 -- Reset the profile before copying
563 DBObjectLib.ResetProfile(self, nil, true)
565 local profile = self.profile
566 local source = self.profiles[name]
568 copyTable(source, profile)
570 -- populate to child namespaces
571 if self.children then
572 for _, db in pairs(self.children) do
573 DBObjectLib.CopyProfile(db, name, true)
577 -- Callback: OnProfileCopied, database, sourceProfileKey
578 self.callbacks:Fire("OnProfileCopied", self, name)
581 --- Resets the current profile to the default values (if specified).
582 -- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
583 -- @param noCallbacks if set to true, won't fire the OnProfileReset callback
584 function DBObjectLib:ResetProfile(noChildren, noCallbacks)
585 local profile = self.profile
587 for k,v in pairs(profile) do
591 local defaults = self.defaults and self.defaults.profile
593 copyDefaults(profile, defaults)
596 -- populate to child namespaces
597 if self.children and not noChildren then
598 for _, db in pairs(self.children) do
599 DBObjectLib.ResetProfile(db, nil, noCallbacks)
603 -- Callback: OnProfileReset, database
604 if not noCallbacks then
605 self.callbacks:Fire("OnProfileReset", self)
609 --- Resets the entire database, using the string defaultProfile as the new default
611 -- @param defaultProfile The profile name to use as the default
612 function DBObjectLib:ResetDB(defaultProfile)
613 if defaultProfile and type(defaultProfile) ~= "string" then
614 error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2)
618 for k,v in pairs(sv) do
622 local parent = self.parent
624 initdb(sv, self.defaults, defaultProfile, self)
626 -- fix the child namespaces
627 if self.children then
628 if not sv.namespaces then sv.namespaces = {} end
629 for name, db in pairs(self.children) do
630 if not sv.namespaces[name] then sv.namespaces[name] = {} end
631 initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
635 -- Callback: OnDatabaseReset, database
636 self.callbacks:Fire("OnDatabaseReset", self)
637 -- Callback: OnProfileChanged, database, profileKey
638 self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
643 --- Creates a new database namespace, directly tied to the database. This
644 -- is a full scale database in it's own rights other than the fact that
645 -- it cannot control its profile individually
646 -- @param name The name of the new namespace
647 -- @param defaults A table of values to use as defaults
648 function DBObjectLib:RegisterNamespace(name, defaults)
649 if type(name) ~= "string" then
650 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2)
652 if defaults and type(defaults) ~= "table" then
653 error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2)
655 if self.children and self.children[name] then
656 error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 2)
660 if not sv.namespaces then sv.namespaces = {} end
661 if not sv.namespaces[name] then
662 sv.namespaces[name] = {}
665 local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
667 if not self.children then self.children = {} end
668 self.children[name] = newDB
672 --- Returns an already existing namespace from the database object.
673 -- @param name The name of the new namespace
674 -- @param silent if true, the addon is optional, silently return nil if its not found
676 -- local namespace = self.db:GetNamespace('namespace')
677 -- @return the namespace object if found
678 function DBObjectLib:GetNamespace(name, silent)
679 if type(name) ~= "string" then
680 error("Usage: AceDBObject:GetNamespace(name): 'name' - string expected.", 2)
682 if not silent and not (self.children and self.children[name]) then
683 error ("Usage: AceDBObject:GetNamespace(name): 'name' - namespace does not exist.", 2)
685 if not self.children then self.children = {} end
686 return self.children[name]
689 --[[-------------------------------------------------------------------------
690 AceDB Exposed Methods
691 ---------------------------------------------------------------------------]]
693 --- Creates a new database object that can be used to handle database settings and profiles.
694 -- By default, an empty DB is created, using a character specific profile.
696 -- You can override the default profile used by passing any profile name as the third argument,
697 -- or by passing //true// as the third argument to use a globally shared profile called "Default".
699 -- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
700 -- will use a profile named "char", and not a character-specific profile.
701 -- @param tbl The name of variable, or table to use for the database
702 -- @param defaults A table of database defaults
703 -- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
704 -- You can also pass //true// to use a shared global profile called "Default".
706 -- -- Create an empty DB using a character-specific default profile.
707 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
709 -- -- Create a DB using defaults and using a shared default profile
710 -- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
711 function AceDB:New(tbl, defaults, defaultProfile)
712 if type(tbl) == "string" then
721 if type(tbl) ~= "table" then
722 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2)
725 if defaults and type(defaults) ~= "table" then
726 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2)
729 if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
730 error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected.", 2)
733 return initdb(tbl, defaults, defaultProfile)
736 -- upgrade existing databases
737 for db in pairs(AceDB.db_registry) do
738 if not db.parent then
739 for name,func in pairs(DBObjectLib) do
743 db.RegisterDefaults = DBObjectLib.RegisterDefaults
744 db.ResetProfile = DBObjectLib.ResetProfile