You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
741 lines
24 KiB
741 lines
24 KiB
--- **AceDB-3.0** manages the SavedVariables of your addon. |
|
-- It offers profile management, smart defaults and namespaces for modules.\\ |
|
-- Data can be saved in different data-types, depending on its intended usage. |
|
-- The most common data-type is the `profile` type, which allows the user to choose |
|
-- the active profile, and manage the profiles of all of his characters.\\ |
|
-- The following data types are available: |
|
-- * **char** Character-specific data. Every character has its own database. |
|
-- * **realm** Realm-specific data. All of the players characters on the same realm share this database. |
|
-- * **class** Class-specific data. All of the players characters of the same class share this database. |
|
-- * **race** Race-specific data. All of the players characters of the same race share this database. |
|
-- * **faction** Faction-specific data. All of the players characters of the same faction share this database. |
|
-- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database. |
|
-- * **locale** Locale specific data, based on the locale of the players game client. |
|
-- * **global** Global Data. All characters on the same account share this database. |
|
-- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used. |
|
-- |
|
-- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions |
|
-- of the DBObjectLib listed here. \\ |
|
-- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note |
|
-- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that, |
|
-- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases. |
|
-- |
|
-- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]]. |
|
-- |
|
-- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs. |
|
-- |
|
-- @usage |
|
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample") |
|
-- |
|
-- -- declare defaults to be used in the DB |
|
-- local defaults = { |
|
-- profile = { |
|
-- setting = true, |
|
-- } |
|
-- } |
|
-- |
|
-- function MyAddon:OnInitialize() |
|
-- -- Assuming the .toc says ## SavedVariables: MyAddonDB |
|
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true) |
|
-- end |
|
-- @class file |
|
-- @name AceDB-3.0.lua |
|
-- @release $Id$ |
|
local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 27 |
|
local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR) |
|
|
|
if not AceDB then return end -- No upgrade needed |
|
|
|
-- Lua APIs |
|
local type, pairs, next, error = type, pairs, next, error |
|
local setmetatable, rawset, rawget = setmetatable, rawset, rawget |
|
|
|
-- WoW APIs |
|
local _G = _G |
|
|
|
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded |
|
-- List them here for Mikk's FindGlobals script |
|
-- GLOBALS: LibStub |
|
|
|
AceDB.db_registry = AceDB.db_registry or {} |
|
AceDB.frame = AceDB.frame or CreateFrame("Frame") |
|
|
|
local CallbackHandler |
|
local CallbackDummy = { Fire = function() end } |
|
|
|
local DBObjectLib = {} |
|
|
|
--[[------------------------------------------------------------------------- |
|
AceDB Utility Functions |
|
---------------------------------------------------------------------------]] |
|
|
|
-- Simple shallow copy for copying defaults |
|
local function copyTable(src, dest) |
|
if type(dest) ~= "table" then dest = {} end |
|
if type(src) == "table" then |
|
for k,v in pairs(src) do |
|
if type(v) == "table" then |
|
-- try to index the key first so that the metatable creates the defaults, if set, and use that table |
|
v = copyTable(v, dest[k]) |
|
end |
|
dest[k] = v |
|
end |
|
end |
|
return dest |
|
end |
|
|
|
-- Called to add defaults to a section of the database |
|
-- |
|
-- When a ["*"] default section is indexed with a new key, a table is returned |
|
-- and set in the host table. These tables must be cleaned up by removeDefaults |
|
-- in order to ensure we don't write empty default tables. |
|
local function copyDefaults(dest, src) |
|
-- this happens if some value in the SV overwrites our default value with a non-table |
|
--if type(dest) ~= "table" then return end |
|
for k, v in pairs(src) do |
|
if k == "*" or k == "**" then |
|
if type(v) == "table" then |
|
-- This is a metatable used for table defaults |
|
local mt = { |
|
-- This handles the lookup and creation of new subtables |
|
__index = function(t,k) |
|
if k == nil then return nil end |
|
local tbl = {} |
|
copyDefaults(tbl, v) |
|
rawset(t, k, tbl) |
|
return tbl |
|
end, |
|
} |
|
setmetatable(dest, mt) |
|
-- handle already existing tables in the SV |
|
for dk, dv in pairs(dest) do |
|
if not rawget(src, dk) and type(dv) == "table" then |
|
copyDefaults(dv, v) |
|
end |
|
end |
|
else |
|
-- Values are not tables, so this is just a simple return |
|
local mt = {__index = function(t,k) return k~=nil and v or nil end} |
|
setmetatable(dest, mt) |
|
end |
|
elseif type(v) == "table" then |
|
if not rawget(dest, k) then rawset(dest, k, {}) end |
|
if type(dest[k]) == "table" then |
|
copyDefaults(dest[k], v) |
|
if src['**'] then |
|
copyDefaults(dest[k], src['**']) |
|
end |
|
end |
|
else |
|
if rawget(dest, k) == nil then |
|
rawset(dest, k, v) |
|
end |
|
end |
|
end |
|
end |
|
|
|
-- Called to remove all defaults in the default table from the database |
|
local function removeDefaults(db, defaults, blocker) |
|
-- remove all metatables from the db, so we don't accidentally create new sub-tables through them |
|
setmetatable(db, nil) |
|
-- loop through the defaults and remove their content |
|
for k,v in pairs(defaults) do |
|
if k == "*" or k == "**" then |
|
if type(v) == "table" then |
|
-- Loop through all the actual k,v pairs and remove |
|
for key, value in pairs(db) do |
|
if type(value) == "table" then |
|
-- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables |
|
if defaults[key] == nil and (not blocker or blocker[key] == nil) then |
|
removeDefaults(value, v) |
|
-- if the table is empty afterwards, remove it |
|
if next(value) == nil then |
|
db[key] = nil |
|
end |
|
-- if it was specified, only strip ** content, but block values which were set in the key table |
|
elseif k == "**" then |
|
removeDefaults(value, v, defaults[key]) |
|
end |
|
end |
|
end |
|
elseif k == "*" then |
|
-- check for non-table default |
|
for key, value in pairs(db) do |
|
if defaults[key] == nil and v == value then |
|
db[key] = nil |
|
end |
|
end |
|
end |
|
elseif type(v) == "table" and type(db[k]) == "table" then |
|
-- if a blocker was set, dive into it, to allow multi-level defaults |
|
removeDefaults(db[k], v, blocker and blocker[k]) |
|
if next(db[k]) == nil then |
|
db[k] = nil |
|
end |
|
else |
|
-- check if the current value matches the default, and that its not blocked by another defaults table |
|
if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then |
|
db[k] = nil |
|
end |
|
end |
|
end |
|
end |
|
|
|
-- This is called when a table section is first accessed, to set up the defaults |
|
local function initSection(db, section, svstore, key, defaults) |
|
local sv = rawget(db, "sv") |
|
|
|
local tableCreated |
|
if not sv[svstore] then sv[svstore] = {} end |
|
if not sv[svstore][key] then |
|
sv[svstore][key] = {} |
|
tableCreated = true |
|
end |
|
|
|
local tbl = sv[svstore][key] |
|
|
|
if defaults then |
|
copyDefaults(tbl, defaults) |
|
end |
|
rawset(db, section, tbl) |
|
|
|
return tableCreated, tbl |
|
end |
|
|
|
-- Metatable to handle the dynamic creation of sections and copying of sections. |
|
local dbmt = { |
|
__index = function(t, section) |
|
local keys = rawget(t, "keys") |
|
local key = keys[section] |
|
if key then |
|
local defaultTbl = rawget(t, "defaults") |
|
local defaults = defaultTbl and defaultTbl[section] |
|
|
|
if section == "profile" then |
|
local new = initSection(t, section, "profiles", key, defaults) |
|
if new then |
|
-- Callback: OnNewProfile, database, newProfileKey |
|
t.callbacks:Fire("OnNewProfile", t, key) |
|
end |
|
elseif section == "profiles" then |
|
local sv = rawget(t, "sv") |
|
if not sv.profiles then sv.profiles = {} end |
|
rawset(t, "profiles", sv.profiles) |
|
elseif section == "global" then |
|
local sv = rawget(t, "sv") |
|
if not sv.global then sv.global = {} end |
|
if defaults then |
|
copyDefaults(sv.global, defaults) |
|
end |
|
rawset(t, section, sv.global) |
|
else |
|
initSection(t, section, section, key, defaults) |
|
end |
|
end |
|
|
|
return rawget(t, section) |
|
end |
|
} |
|
|
|
local function validateDefaults(defaults, keyTbl, offset) |
|
if not defaults then return end |
|
offset = offset or 0 |
|
for k in pairs(defaults) do |
|
if not keyTbl[k] or k == "profiles" then |
|
error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset) |
|
end |
|
end |
|
end |
|
|
|
local preserve_keys = { |
|
["callbacks"] = true, |
|
["RegisterCallback"] = true, |
|
["UnregisterCallback"] = true, |
|
["UnregisterAllCallbacks"] = true, |
|
["children"] = true, |
|
} |
|
|
|
local realmKey = GetRealmName() |
|
local charKey = UnitName("player") .. " - " .. realmKey |
|
local _, classKey = UnitClass("player") |
|
local _, raceKey = UnitRace("player") |
|
local factionKey = UnitFactionGroup("player") |
|
local factionrealmKey = factionKey .. " - " .. realmKey |
|
local factionrealmregionKey = factionrealmKey .. " - " .. string.sub(GetCVar("realmList"), 1, 2):upper() |
|
local localeKey = GetLocale():lower() |
|
|
|
-- Actual database initialization function |
|
local function initdb(sv, defaults, defaultProfile, olddb, parent) |
|
-- Generate the database keys for each section |
|
|
|
-- map "true" to our "Default" profile |
|
if defaultProfile == true then defaultProfile = "Default" end |
|
|
|
local profileKey |
|
if not parent then |
|
-- Make a container for profile keys |
|
if not sv.profileKeys then sv.profileKeys = {} end |
|
|
|
-- Try to get the profile selected from the char db |
|
profileKey = sv.profileKeys[charKey] or defaultProfile or charKey |
|
|
|
-- save the selected profile for later |
|
sv.profileKeys[charKey] = profileKey |
|
else |
|
-- Use the profile of the parents DB |
|
profileKey = parent.keys.profile or defaultProfile or charKey |
|
|
|
-- clear the profileKeys in the DB, namespaces don't need to store them |
|
sv.profileKeys = nil |
|
end |
|
|
|
-- This table contains keys that enable the dynamic creation |
|
-- of each section of the table. The 'global' and 'profiles' |
|
-- have a key of true, since they are handled in a special case |
|
local keyTbl= { |
|
["char"] = charKey, |
|
["realm"] = realmKey, |
|
["class"] = classKey, |
|
["race"] = raceKey, |
|
["faction"] = factionKey, |
|
["factionrealm"] = factionrealmKey, |
|
["factionrealmregion"] = factionrealmregionKey, |
|
["profile"] = profileKey, |
|
["locale"] = localeKey, |
|
["global"] = true, |
|
["profiles"] = true, |
|
} |
|
|
|
validateDefaults(defaults, keyTbl, 1) |
|
|
|
-- This allows us to use this function to reset an entire database |
|
-- Clear out the old database |
|
if olddb then |
|
for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end |
|
end |
|
|
|
-- Give this database the metatable so it initializes dynamically |
|
local db = setmetatable(olddb or {}, dbmt) |
|
|
|
if not rawget(db, "callbacks") then |
|
-- try to load CallbackHandler-1.0 if it loaded after our library |
|
if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end |
|
db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy |
|
end |
|
|
|
-- Copy methods locally into the database object, to avoid hitting |
|
-- the metatable when calling methods |
|
|
|
if not parent then |
|
for name, func in pairs(DBObjectLib) do |
|
db[name] = func |
|
end |
|
else |
|
-- hack this one in |
|
db.RegisterDefaults = DBObjectLib.RegisterDefaults |
|
db.ResetProfile = DBObjectLib.ResetProfile |
|
end |
|
|
|
-- Set some properties in the database object |
|
db.profiles = sv.profiles |
|
db.keys = keyTbl |
|
db.sv = sv |
|
--db.sv_name = name |
|
db.defaults = defaults |
|
db.parent = parent |
|
|
|
-- store the DB in the registry |
|
AceDB.db_registry[db] = true |
|
|
|
return db |
|
end |
|
|
|
-- handle PLAYER_LOGOUT |
|
-- strip all defaults from all databases |
|
-- and cleans up empty sections |
|
local function logoutHandler(frame, event) |
|
if event == "PLAYER_LOGOUT" then |
|
for db in pairs(AceDB.db_registry) do |
|
db.callbacks:Fire("OnDatabaseShutdown", db) |
|
db:RegisterDefaults(nil) |
|
|
|
-- cleanup sections that are empty without defaults |
|
local sv = rawget(db, "sv") |
|
for section in pairs(db.keys) do |
|
if rawget(sv, section) then |
|
-- global is special, all other sections have sub-entrys |
|
-- also don't delete empty profiles on main dbs, only on namespaces |
|
if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then |
|
for key in pairs(sv[section]) do |
|
if not next(sv[section][key]) then |
|
sv[section][key] = nil |
|
end |
|
end |
|
end |
|
if not next(sv[section]) then |
|
sv[section] = nil |
|
end |
|
end |
|
end |
|
end |
|
end |
|
end |
|
|
|
AceDB.frame:RegisterEvent("PLAYER_LOGOUT") |
|
AceDB.frame:SetScript("OnEvent", logoutHandler) |
|
|
|
|
|
--[[------------------------------------------------------------------------- |
|
AceDB Object Method Definitions |
|
---------------------------------------------------------------------------]] |
|
|
|
--- Sets the defaults table for the given database object by clearing any |
|
-- that are currently set, and then setting the new defaults. |
|
-- @param defaults A table of defaults for this database |
|
function DBObjectLib:RegisterDefaults(defaults) |
|
if defaults and type(defaults) ~= "table" then |
|
error(("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2) |
|
end |
|
|
|
validateDefaults(defaults, self.keys) |
|
|
|
-- Remove any currently set defaults |
|
if self.defaults then |
|
for section,key in pairs(self.keys) do |
|
if self.defaults[section] and rawget(self, section) then |
|
removeDefaults(self[section], self.defaults[section]) |
|
end |
|
end |
|
end |
|
|
|
-- Set the DBObject.defaults table |
|
self.defaults = defaults |
|
|
|
-- Copy in any defaults, only touching those sections already created |
|
if defaults then |
|
for section,key in pairs(self.keys) do |
|
if defaults[section] and rawget(self, section) then |
|
copyDefaults(self[section], defaults[section]) |
|
end |
|
end |
|
end |
|
end |
|
|
|
--- Changes the profile of the database and all of it's namespaces to the |
|
-- supplied named profile |
|
-- @param name The name of the profile to set as the current profile |
|
function DBObjectLib:SetProfile(name) |
|
if type(name) ~= "string" then |
|
error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2) |
|
end |
|
|
|
-- changing to the same profile, dont do anything |
|
if name == self.keys.profile then return end |
|
|
|
local oldProfile = self.profile |
|
local defaults = self.defaults and self.defaults.profile |
|
|
|
-- Callback: OnProfileShutdown, database |
|
self.callbacks:Fire("OnProfileShutdown", self) |
|
|
|
if oldProfile and defaults then |
|
-- Remove the defaults from the old profile |
|
removeDefaults(oldProfile, defaults) |
|
end |
|
|
|
self.profile = nil |
|
self.keys["profile"] = name |
|
|
|
-- if the storage exists, save the new profile |
|
-- this won't exist on namespaces. |
|
if self.sv.profileKeys then |
|
self.sv.profileKeys[charKey] = name |
|
end |
|
|
|
-- populate to child namespaces |
|
if self.children then |
|
for _, db in pairs(self.children) do |
|
DBObjectLib.SetProfile(db, name) |
|
end |
|
end |
|
|
|
-- Callback: OnProfileChanged, database, newProfileKey |
|
self.callbacks:Fire("OnProfileChanged", self, name) |
|
end |
|
|
|
--- Returns a table with the names of the existing profiles in the database. |
|
-- You can optionally supply a table to re-use for this purpose. |
|
-- @param tbl A table to store the profile names in (optional) |
|
function DBObjectLib:GetProfiles(tbl) |
|
if tbl and type(tbl) ~= "table" then |
|
error(("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected, got %q."):format(type(tbl)), 2) |
|
end |
|
|
|
-- Clear the container table |
|
if tbl then |
|
for k,v in pairs(tbl) do tbl[k] = nil end |
|
else |
|
tbl = {} |
|
end |
|
|
|
local curProfile = self.keys.profile |
|
|
|
local i = 0 |
|
for profileKey in pairs(self.profiles) do |
|
i = i + 1 |
|
tbl[i] = profileKey |
|
if curProfile and profileKey == curProfile then curProfile = nil end |
|
end |
|
|
|
-- Add the current profile, if it hasn't been created yet |
|
if curProfile then |
|
i = i + 1 |
|
tbl[i] = curProfile |
|
end |
|
|
|
return tbl, i |
|
end |
|
|
|
--- Returns the current profile name used by the database |
|
function DBObjectLib:GetCurrentProfile() |
|
return self.keys.profile |
|
end |
|
|
|
--- Deletes a named profile. This profile must not be the active profile. |
|
-- @param name The name of the profile to be deleted |
|
-- @param silent If true, do not raise an error when the profile does not exist |
|
function DBObjectLib:DeleteProfile(name, silent) |
|
if type(name) ~= "string" then |
|
error(("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected, got %q."):format(type(name)), 2) |
|
end |
|
|
|
if self.keys.profile == name then |
|
error(("Cannot delete the active profile (%q) in an AceDBObject."):format(name), 2) |
|
end |
|
|
|
if not rawget(self.profiles, name) and not silent then |
|
error(("Cannot delete profile %q as it does not exist."):format(name), 2) |
|
end |
|
|
|
self.profiles[name] = nil |
|
|
|
-- populate to child namespaces |
|
if self.children then |
|
for _, db in pairs(self.children) do |
|
DBObjectLib.DeleteProfile(db, name, true) |
|
end |
|
end |
|
|
|
-- switch all characters that use this profile back to the default |
|
if self.sv.profileKeys then |
|
for key, profile in pairs(self.sv.profileKeys) do |
|
if profile == name then |
|
self.sv.profileKeys[key] = nil |
|
end |
|
end |
|
end |
|
|
|
-- Callback: OnProfileDeleted, database, profileKey |
|
self.callbacks:Fire("OnProfileDeleted", self, name) |
|
end |
|
|
|
--- Copies a named profile into the current profile, overwriting any conflicting |
|
-- settings. |
|
-- @param name The name of the profile to be copied into the current profile |
|
-- @param silent If true, do not raise an error when the profile does not exist |
|
function DBObjectLib:CopyProfile(name, silent) |
|
if type(name) ~= "string" then |
|
error(("Usage: AceDBObject:CopyProfile(name): 'name' - string expected, got %q."):format(type(name)), 2) |
|
end |
|
|
|
if name == self.keys.profile then |
|
error(("Cannot have the same source and destination profiles (%q)."):format(name), 2) |
|
end |
|
|
|
if not rawget(self.profiles, name) and not silent then |
|
error(("Cannot copy profile %q as it does not exist."):format(name), 2) |
|
end |
|
|
|
-- Reset the profile before copying |
|
DBObjectLib.ResetProfile(self, nil, true) |
|
|
|
local profile = self.profile |
|
local source = self.profiles[name] |
|
|
|
copyTable(source, profile) |
|
|
|
-- populate to child namespaces |
|
if self.children then |
|
for _, db in pairs(self.children) do |
|
DBObjectLib.CopyProfile(db, name, true) |
|
end |
|
end |
|
|
|
-- Callback: OnProfileCopied, database, sourceProfileKey |
|
self.callbacks:Fire("OnProfileCopied", self, name) |
|
end |
|
|
|
--- Resets the current profile to the default values (if specified). |
|
-- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object |
|
-- @param noCallbacks if set to true, won't fire the OnProfileReset callback |
|
function DBObjectLib:ResetProfile(noChildren, noCallbacks) |
|
local profile = self.profile |
|
|
|
for k,v in pairs(profile) do |
|
profile[k] = nil |
|
end |
|
|
|
local defaults = self.defaults and self.defaults.profile |
|
if defaults then |
|
copyDefaults(profile, defaults) |
|
end |
|
|
|
-- populate to child namespaces |
|
if self.children and not noChildren then |
|
for _, db in pairs(self.children) do |
|
DBObjectLib.ResetProfile(db, nil, noCallbacks) |
|
end |
|
end |
|
|
|
-- Callback: OnProfileReset, database |
|
if not noCallbacks then |
|
self.callbacks:Fire("OnProfileReset", self) |
|
end |
|
end |
|
|
|
--- Resets the entire database, using the string defaultProfile as the new default |
|
-- profile. |
|
-- @param defaultProfile The profile name to use as the default |
|
function DBObjectLib:ResetDB(defaultProfile) |
|
if defaultProfile and type(defaultProfile) ~= "string" then |
|
error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected, got %q."):format(type(defaultProfile)), 2) |
|
end |
|
|
|
local sv = self.sv |
|
for k,v in pairs(sv) do |
|
sv[k] = nil |
|
end |
|
|
|
initdb(sv, self.defaults, defaultProfile, self) |
|
|
|
-- fix the child namespaces |
|
if self.children then |
|
if not sv.namespaces then sv.namespaces = {} end |
|
for name, db in pairs(self.children) do |
|
if not sv.namespaces[name] then sv.namespaces[name] = {} end |
|
initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self) |
|
end |
|
end |
|
|
|
-- Callback: OnDatabaseReset, database |
|
self.callbacks:Fire("OnDatabaseReset", self) |
|
-- Callback: OnProfileChanged, database, profileKey |
|
self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"]) |
|
|
|
return self |
|
end |
|
|
|
--- Creates a new database namespace, directly tied to the database. This |
|
-- is a full scale database in it's own rights other than the fact that |
|
-- it cannot control its profile individually |
|
-- @param name The name of the new namespace |
|
-- @param defaults A table of values to use as defaults |
|
function DBObjectLib:RegisterNamespace(name, defaults) |
|
if type(name) ~= "string" then |
|
error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected, got %q."):format(type(name)), 2) |
|
end |
|
if defaults and type(defaults) ~= "table" then |
|
error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2) |
|
end |
|
if self.children and self.children[name] then |
|
error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace called %q already exists."):format(name), 2) |
|
end |
|
|
|
local sv = self.sv |
|
if not sv.namespaces then sv.namespaces = {} end |
|
if not sv.namespaces[name] then |
|
sv.namespaces[name] = {} |
|
end |
|
|
|
local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self) |
|
|
|
if not self.children then self.children = {} end |
|
self.children[name] = newDB |
|
return newDB |
|
end |
|
|
|
--- Returns an already existing namespace from the database object. |
|
-- @param name The name of the new namespace |
|
-- @param silent if true, the addon is optional, silently return nil if its not found |
|
-- @usage |
|
-- local namespace = self.db:GetNamespace('namespace') |
|
-- @return the namespace object if found |
|
function DBObjectLib:GetNamespace(name, silent) |
|
if type(name) ~= "string" then |
|
error(("Usage: AceDBObject:GetNamespace(name): 'name' - string expected, got %q."):format(type(name)), 2) |
|
end |
|
if not silent and not (self.children and self.children[name]) then |
|
error(("Usage: AceDBObject:GetNamespace(name): 'name' - namespace %q does not exist."):format(name), 2) |
|
end |
|
if not self.children then self.children = {} end |
|
return self.children[name] |
|
end |
|
|
|
--[[------------------------------------------------------------------------- |
|
AceDB Exposed Methods |
|
---------------------------------------------------------------------------]] |
|
|
|
--- Creates a new database object that can be used to handle database settings and profiles. |
|
-- By default, an empty DB is created, using a character specific profile. |
|
-- |
|
-- You can override the default profile used by passing any profile name as the third argument, |
|
-- or by passing //true// as the third argument to use a globally shared profile called "Default". |
|
-- |
|
-- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char" |
|
-- will use a profile named "char", and not a character-specific profile. |
|
-- @param tbl The name of variable, or table to use for the database |
|
-- @param defaults A table of database defaults |
|
-- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default. |
|
-- You can also pass //true// to use a shared global profile called "Default". |
|
-- @usage |
|
-- -- Create an empty DB using a character-specific default profile. |
|
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB") |
|
-- @usage |
|
-- -- Create a DB using defaults and using a shared default profile |
|
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true) |
|
function AceDB:New(tbl, defaults, defaultProfile) |
|
if type(tbl) == "string" then |
|
local name = tbl |
|
tbl = _G[name] |
|
if not tbl then |
|
tbl = {} |
|
_G[name] = tbl |
|
end |
|
end |
|
|
|
if type(tbl) ~= "table" then |
|
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected, got %q."):format(type(tbl)), 2) |
|
end |
|
|
|
if defaults and type(defaults) ~= "table" then |
|
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2) |
|
end |
|
|
|
if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then |
|
error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2) |
|
end |
|
|
|
return initdb(tbl, defaults, defaultProfile) |
|
end |
|
|
|
-- upgrade existing databases |
|
for db in pairs(AceDB.db_registry) do |
|
if not db.parent then |
|
for name,func in pairs(DBObjectLib) do |
|
db[name] = func |
|
end |
|
else |
|
db.RegisterDefaults = DBObjectLib.RegisterDefaults |
|
db.ResetProfile = DBObjectLib.ResetProfile |
|
end |
|
end
|
|
|