From a50809f801785b9854762fbbaa5407315c70b44a Mon Sep 17 00:00:00 2001 From: Stephen Leitnick Date: Tue, 21 May 2019 18:28:18 -0400 Subject: [PATCH] Add comments --- src/ServerStorage/Aero/Modules/Data.lua | 58 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/ServerStorage/Aero/Modules/Data.lua b/src/ServerStorage/Aero/Modules/Data.lua index 92955fe..1f8aae9 100644 --- a/src/ServerStorage/Aero/Modules/Data.lua +++ b/src/ServerStorage/Aero/Modules/Data.lua @@ -39,7 +39,6 @@ data.Success data.Success:Connect(String method, String key) data.Failed data.Failed:Connect(String method, String key, String err) - METHOD DESCRIPTIONS: Get Gets/loads the value from the key. The optional 'defaultValue' can be used @@ -146,16 +145,17 @@ local Data = {} Data.__index = Data Data._onCloseHandlers = {} +-- Static fields; customize as needed: Data.AutoSaveInterval = 60 Data.PlayerLeftSaveInterval = 10 Data.SaveInStudio = false +-- Constants based on internal Roblox DataStore; DO NOT CHANGE: local NAME_MAX_LEN = 50 local SCOPE_MAX_LEN = 50 local KEY_MAX_LEN = 49 local KEY_MAX_LEN_ERR = "Key must be a string less or equal to " .. KEY_MAX_LEN .. " characters" - local PLAYER_DATA_NAME = "PlayerData" local dataStoreService = game:GetService("DataStoreService") @@ -167,11 +167,12 @@ local tableUtil local Promise +-- Check if key matches DataStore criteria: local function CheckKey(key) return (type(key) == "string" and #key <= KEY_MAX_LEN) end - +-- Retrieve cached DataStore from name and scope: local function GetDataFromNameAndScope(name, scope) local ds = dataStoreService:GetDataStore(name, scope) return dataPool[ds] @@ -213,6 +214,7 @@ end function Data.new(name, scope, ordered) + -- Check arguments: assert(type(name) == "string", "Argument #1 (name) must be a string") assert(type(scope) == "string", "Argument #2 (scope) must be a string") assert(#name <= NAME_MAX_LEN, "Argument #1 (name) must be less or equal to " .. NAME_MAX_LEN .. " characters") @@ -239,6 +241,7 @@ function Data.new(name, scope, ordered) _destroyed = false; }, Data) + -- Data events: self.Success = self.Shared.Event.new() self.Failed = self.Shared.Event.new() @@ -251,6 +254,7 @@ end function Data.ForPlayer(userId, ordered) if (typeof(userId) == "Instance") then + -- Capture UserId from the player object: assert(userId:IsA("Player"), "Expected Player; got " .. userId.ClassName) userId = userId.UserId else @@ -274,6 +278,7 @@ end -- Load a given key from the DataStore: function Data:_load(key) return Promise.new(function(resolve, reject) + -- Call GetAsync and cache the results: local success, value = pcall(self._ds.GetAsync, self._ds, key) if (success) then self._cache[key] = value @@ -300,9 +305,11 @@ end -- Save the key/value to the DataStore: function Data:_save(key, value) if (self._dirty[key] == false) then + -- If not dirty, the given key does not need to be saved: return Promise.Resolve() end return Promise.new(function(resolve, reject) + -- Call SetAsync and mark key as no longer dirty: local valBeforeSave = self:_getCache(key) local success, err = pcall(self._ds.SetAsync, self._ds, key, value) if (success) then @@ -321,6 +328,7 @@ end function Data:_delete(key) return Promise.new(function(resolve, reject) + -- Call RemoveAsync and remove value from cache: local success, err = pcall(self._ds.RemoveAsync, self._ds, key) if (success) then self:_clearCache(key) @@ -336,6 +344,7 @@ end function Data:_update(key, transformFunc) return Promise.new(function(resolve, reject) + -- Call UpdateAsync and update cache with returned value: local success, value = pcall(self._ds.UpdateAsync, self._ds, key, transformFunc) if (success) then self:_setCache(key, value, true) @@ -349,11 +358,26 @@ function Data:_update(key, transformFunc) end +function Data:_getSorted(isAscending, pageSize, minValue, maxValue) + return Promise.new(function(resolve, reject) + -- Call GetSortedAsync and return the custom DataStorePages object: + local success, dsp = pcall(self._ds.GetSortedAsync, self._ods, isAscending, pageSize, minValue, maxValue) + if (success) then + resolve(DataStorePages.new(dsp)) + else + reject(dsp) + end + end, true) +end + + +-- Retrieve a cached value for the given key: function Data:_getCache(key) return self._cache[key] end +-- Set an item in the cache and mark clean or dirty: function Data:_setCache(key, value, isClean) if (self._cache[key] ~= value) then self._cache[key] = value @@ -362,17 +386,20 @@ function Data:_setCache(key, value, isClean) end +-- Delete an item from the cache: function Data:_clearCache(key) self._cache[key] = nil self._dirty[key] = nil end +-- Check if a key has a value in the cache: function Data:_cacheExists(key) return (self._cache[key] ~= nil) end +-- Get the number of keys within the cache: function Data:_countKeysInCache() local keyCount = 0 for _ in pairs(self._cache) do @@ -382,23 +409,15 @@ function Data:_countKeysInCache() end -function Data:_getSorted(isAscending, pageSize, minValue, maxValue) - return Promise.new(function(resolve, reject) - local success, dsp = pcall(self._ds.GetSortedAsync, self._ods, isAscending, pageSize, minValue, maxValue) - if (success) then - resolve(DataStorePages.new(dsp)) - else - reject(dsp) - end - end, true) -end - - --------------------------------------------------------------------------------------------------------------------------- -- PUBLIC METHODS: function Data:GetRequestBudget(reqType) + -- See: + -- https://developer.roblox.com/api-reference/function/DataStoreService/GetRequestBudgetForRequestType + -- https://developer.roblox.com/api-reference/enum/DataStoreRequestType + -- https://developer.roblox.com/articles/Datastore-Errors return dataStoreService:GetRequestBudgetForRequestType(reqType) end @@ -411,8 +430,10 @@ function Data:Get(key, defaultVal) return Promise.Reject(KEY_MAX_LEN_ERR) end if (self:_cacheExists(key)) then + -- Return the cached value: return Promise.Resolve(self:_getCache(key)) end + -- Load and return value since it was not in the cache: return self:_load(key):Then(function(value) if (value == nil and defaultVal ~= nil) then value = (typeof(defaultVal) ~= "table" and defaultVal or tableUtil.Copy(defaultVal)) @@ -461,6 +482,7 @@ function Data:Increment(key, increment) if (type(increment) ~= "number") then return Promise.Reject("Increment must be a number") end + -- Get the current value, increment it, then set the new value: return self:Get(key, 0):Then(function(value) if (type(value) ~= "number") then error("Cannot increment a non-number value") @@ -521,6 +543,7 @@ function Data:SaveAll() if (self._destroyed) then return Promise.Reject("Data already destroyed") end + -- Collect all 'Save' promises and return them all in a single promise: local promises = {} for key in pairs(self._cache) do promises[#promises + 1] = self:Save(key) @@ -555,12 +578,14 @@ function Data:Destroy(save) savePromise = Promise.Resolve() end return savePromise:Then(function() + -- Clear and destroy objects: self._cache = {} self._dirty = {} self.Failed:Destroy() self.Success:Destroy() dataPool[self._ds] = nil end):Catch(function(err) + -- Failed to destroy, thus remark as not destroyed & rethrow error: self._destroyed = false error(err) end) @@ -592,7 +617,8 @@ function Data:Start() if (not Data.SaveInStudio) then Data.IsUsingMockService = true else - local success,err = pcall(function() + -- Verify status of the DataStoreService on startup: + local success, err = pcall(function() dataStoreService:GetDataStore("__aero"):UpdateAsync("dss_api_check", function(v) return v == nil and true or v end) end) if (not success) then