How could I improve this datastore wrapper?

so, I’ve written a datastore wrapper, and if I just look over it, it feels like something can be optimized/rewritten, any suggestions?

and yes, I use a main datastore and a backup datastore, I also have discord & gameanalytics logging, before you start ranting at me for using discord logging, I’m going to remove that after a while, when I fully get my gameanalytics working.

local workspace = game:GetService("Workspace")
local players = game:GetService("Players")
local coregui = game:GetService("CoreGui")
local lighting = game:GetService("Lighting")
local replicated = game:GetService("ReplicatedStorage")
local serverscriptservice = game:GetService("ServerScriptService")
local serverstorage = game:GetService("ServerStorage")
local startergui = game:GetService("StarterGui")
local datastoreservice = game:GetService("DataStoreService")
local messagingservice = game:GetService("MessagingService")
local httpservice = game:GetService("HttpService")

-- /*/ Dependencies
local gameAnalytics = require(serverstorage:WaitForChild("GameAnalytics"))
local configurationDatatable = require(replicated.Modules.Datatables:WaitForChild("ConfigurationDatatable"))

-- /*/ Internal Functions
local printDebug = function(debugMode, debugSide, debugMessage)
	local debugConfigurations = configurationDatatable.debugConfigurations
	if debugSide == "Server" then
		local debugStatuses = debugConfigurations["SERVER_DEBUGS"]
		if debugStatuses[debugMode] == true then
			print(debugMessage)
		end
	elseif debugSide == "Client" then
		local debugStatuses = debugConfigurations["CLIENT_DEBUGS"]
		if debugStatuses[debugMode] == true then
			print(debugMessage)
		end
	end
end

local functions = {}
local library = {}

-----------------------------------------------------------------------
------------------------------- Library -------------------------------
-----------------------------------------------------------------------

local dataCache = {}

function functions:GetDatastoreData(player, datastore, backupDatastore, datastoreKey)
	printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Starting datastore retrieval...")
	
	-- /*/ Retrieving dat
	local data, backupData = {}, {}
	local success, errorMessage = pcall(function()
		data = datastore:GetAsync(datastoreKey)
	end)
	local success1, errorMessage1 = pcall(function()
		backupData = datastore:GetAsync(datastoreKey)
	end)
	
	if success and not errorMessage then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully loaded data (KEY: " .. datastoreKey .. ") from main datastore!")
	elseif not success and errorMessage then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to load data (KEY: " .. datastoreKey .. ") from main datastore! Recieved error: " .. errorMessage)
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.critical,
			message = errorMessage
		})
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.info,
			message = "Failed to save: " .. player.Name .. "'s main data! | DataKey: " .. tostring(httpservice:JSONEncode(data))
		})
		replicated.Remotes.ServerCommunication.ModerationHandler:Fire("Logging", "DiscordWebhook", "DatastoreLogger", {
			["content"] = "",
			["embeds"] = {{
				["title"] = "**Oahu Datastore Status**",
				["description"] = player.Name .. "'s main data failed to save!",
				["type"] = "rich",
				["color"] = tonumber(0xff0000),
				["fields"] = {
					{
						["name"] = "__DataKey:__",
						["value"] = tostring(httpservice:JSONEncode(data)),
						["inline"] = true
					},
					{
						["name"] = "__Recieved Error:__",
						["value"] = errorMessage,
						["inline"] = true
					}
				}
			}}
		})
	end
	if success1 and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully loaded data (KEY: " .. datastoreKey .. ") from backup datastore!")
	elseif not success1 and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to load data (KEY: " .. datastoreKey .. ") from backup datastore! Recieved error: " .. errorMessage1)
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.critical,
			message = errorMessage1
		})
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.info,
			message = "Failed to save: " .. player.Name .. "'s backup data! | DataKey: " .. tostring(httpservice:JSONEncode(data))
		})
		replicated.Remotes.ServerCommunication.ModerationHandler:Fire("Logging", "DiscordWebhook", "DatastoreLogger", {
			["content"] = "",
			["embeds"] = {{
				["title"] = "**Oahu Datastore Status**",
				["description"] = player.Name .. "'s backup data failed to save!",
				["type"] = "rich",
				["color"] = tonumber(0xff0000),
				["fields"] = {
					{
						["name"] = "__DataKey:__",
						["value"] = tostring(httpservice:JSONEncode(data)),
						["inline"] = true
					},
					{
						["name"] = "__Recieved Error:__",
						["value"] = errorMessage1,
						["inline"] = true
					}
				}
			}}
		})
	end
	if success and success1 and not errorMessage and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully loaded data (KEY: " .. datastoreKey .. ") from main & backup datastore!")
		return {
			["status"] = "Successfully loaded data from main & backup datastore!",
			["data"] = data
		}
	elseif success and not success1 and not errorMessage and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully loaded data (KEY: " .. datastoreKey .. ") from main datastore, but failed to load data from backup datastore.")
		return {
			["status"] = "Successfully loaded data from main datastore, but failed to load data from backup datastore.",
			["data"] = data
		}
	elseif not success and success1 and errorMessage and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to load data (KEY: " .. datastoreKey .. ") from main datastore, but succeeded in loading data from the backup datastore.")
		return {
			["status"] = "Failed to load data from main datastore, but succeeded in loading data from the backup datastore.",
			["data"] = backupData
		}
	elseif not success and not success1 and errorMessage and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to load data (KEY: " .. datastoreKey .. ") from either datastores.")
		return {
			["status"] = "Failed to load data from either datastores.",
			["data"] = nil
		}
	end
	
	-- /*/ Error Handling
--	if success and not errorMessage then
--		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully retrieved data!")
--		dataCache[player] = data
--		return {
--			["status"] = "OK.",
--			["data"] = data,
--			["errorMessage"] = "None"
--		}
--	elseif not success and errorMessage then
--		
--		-- /*/ Logging
--		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to retrieve main data! Error: " .. errorMessage)
--		gameAnalytics:addErrorEvent(player.UserId, {
--			severity = gameAnalytics.EGAErrorSeverity.critical,
--			message = errorMessage
--		})
--		replicated.Remotes.ServerCommunication.ModerationHandler:Fire("Logging", "DiscordWebhook", "DatastoreLogger", {
--			["content"] = "",
--			["embeds"] = {{
--				["title"] = "__**Oahu Datastore Status**__",
--				["description"] = player.Name .. "'s data failed to load!",
--				["type"] = "rich",
--				["color"] = tonumber(0xff0000),
--				["fields"] = {
--					{
--						["name"] = "__Recieved Error:__",
--						["value"] = errorMessage,
--						["inline"] = true
--					}
--				}
--			}}
--		})
--		
--		return {
--			["status"] = "Failed to retrieve data!",
--			["data"] = data,
--			["errorMessage"] = errorMessage
--		}
--	elseif success and not data then
--		return {	
--			["status"] = "No saved data!",
--			["data"] = nil,	
--		}
--	end
end

function functions:SetDatastoreData(player, datastore, backupDatastore, datastoreKey, data)
	printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Starting datastore saving...")
	
	local success, errorMessage = pcall(function()
		datastore:SetAsync(datastoreKey, data)
	end)
	local success1, errorMessage1 = pcall(function()
		backupDatastore:SetAsync(datastoreKey, data)
	end)
	
	if success and not errorMessage then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully saved to main datastore!")
	elseif not success and errorMessage then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to save to main datastore! Recieved error: " .. errorMessage)
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.critical,
			message = errorMessage
		})
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.info,
			message = "Failed to save: " .. player.Name .. "'s main data! | DataKey: " .. tostring(httpservice:JSONEncode(data))
		})
		replicated.Remotes.ServerCommunication.ModerationHandler:Fire("Logging", "DiscordWebhook", "DatastoreLogger", {
			["content"] = "",
			["embeds"] = {{
				["title"] = "**Oahu Datastore Status**",
				["description"] = player.Name .. "'s main data failed to save!",
				["type"] = "rich",
				["color"] = tonumber(0xff0000),
				["fields"] = {
					{
						["name"] = "__DataKey:__",
						["value"] = tostring(httpservice:JSONEncode(data)),
						["inline"] = true
					},
					{
						["name"] = "__Recieved Error:__",
						["value"] = errorMessage,
						["inline"] = true
					}
				}
			}}
		})
	end
	if success1 and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully saved to backup datastore!")
	elseif not success1 and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to save to backup datastore! Recieved error: " .. errorMessage1)
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.critical,
			message = errorMessage1
		})
		gameAnalytics:addErrorEvent(player.UserId, {
			severity = gameAnalytics.EGAErrorSeverity.info,
			message = "Failed to save: " .. player.Name .. "'s backup data! | DataKey: " .. tostring(httpservice:JSONEncode(data))
		})
		replicated.Remotes.ServerCommunication.ModerationHandler:Fire("Logging", "DiscordWebhook", "DatastoreLogger", {
			["content"] = "",
			["embeds"] = {{
				["title"] = "**Oahu Datastore Status**",
				["description"] = player.Name .. "'s backup data failed to save!",
				["type"] = "rich",
				["color"] = tonumber(0xff0000),
				["fields"] = {
					{
						["name"] = "__DataKey:__",
						["value"] = tostring(httpservice:JSONEncode(data)),
						["inline"] = true
					},
					{
						["name"] = "__Recieved Error:__",
						["value"] = errorMessage1,
						["inline"] = true
					}
				}
			}}
		})
	end
	if success and success1 and not errorMessage and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully saved to main & backup datastore!")
		return {
			["status"] = "Successfully saved to main & backup datastore!",
			["data"] = data
		}
	elseif success and not success1 and not errorMessage and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Successfully saved to main datastore, but failed to save to backup datastore.")
		return {
			["status"] = "Successfully saved to main datastore, but failed to save to backup datastore.",
			["data"] = data
		}
	elseif not success and success1 and errorMessage and not errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to save to main datastore, but succeeded in saving to the backup datastore.")
		return {
			["status"] = "Failed to save to main datastore, but succeeded in saving to the backup datastore.",
			["data"] = data
		}
	elseif not success and not success1 and errorMessage and errorMessage1 then
		printDebug("Datastore_Debugging", "Server", "[DatastoreHandler]: Failed to save to either datastores.")
		return {
			["status"] = "Failed to save to either datastores.",
			["data"] = data
		}
	end
end

return functions
3 Likes

I’d say, before you get any meaningful review, please remove extraneous variables and code and adopt a consistent way of styling your codebase.

And, while it seems you’re already aware that Discord logging should not be used, I would advise simply scratching that part and implementing proper logging next time in your initial design phase.

1 Like