How could I improve my DataStore module?

Just wondering if there is anything I could do to optimize/make this module perform better.

Script:

--// Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")

--// Locals
local PlayerDataHandler = {}

local Framework = require(ReplicatedStorage:FindFirstChild("Framework"))

local Modules = ServerStorage:FindFirstChild("Modules")
local Constants = require(Modules:FindFirstChild("Constants"))
local PlayerDataTemplate = require(Modules:FindFirstChild("PlayerDataTemplate"))

local DataStore = DataStoreService:GetDataStore(Constants.DataStore)

--// Script
local function GetData(User)
	local Data = nil
	local Success, Error = pcall(function()
		Data = DataStore:GetAsync(User)
	end)

	return Data, Success, Error
end

local function SaveData(User, Data)
	local Success, Error = pcall(function()
		DataStore:SetAsync(User, Data)
	end)
	
	return Success, Error
end

local function MakeData(User)
	local Data = PlayerDataTemplate
	local Success, Error = SaveData(User, PlayerDataTemplate)
	
	if Success then
		Framework:Message("Created data for user:", User)
	end
	
	return Data
end

function PlayerDataHandler:Update(User, Data)
	local SaveDataSuccess = false
	
	for Iteration = 1, Constants.DataStoreUpdateMaxTries do
		local Success, Error = SaveData(User, Data)
		
		if Success then
			SaveDataSuccess = true
			Framework:Message("Saved data for user:", User, "On Try:", (Iteration .. "/" .. Constants.DataStoreUpdateMaxTries))
			break
		else
			Framework:Warn("Failed to save data for user:", User, "On Try:", (Iteration .. "/" .. Constants.DataStoreUpdateMaxTries .. "!"), "Error:", Error)
		end
	end
	
	if not SaveDataSuccess then
		Framework:Warn("Failed to save data for user:", User, "on all " .. Constants.DataStoreUpdateMaxTries .. " tries!")
	end
end

function PlayerDataHandler:Get(User)
	local Data = GetData(User)

	if not Data then
		Framework:Warn("Creating data for user:", User)
		Data = MakeData(User)
	end
	
	return Data
end

return PlayerDataHandler
3 Likes

some good enough modularization

good enough functions that properly encapsulate imperative code to something more useable and translatable into human thought

no performance concerns since this is standard vanilla code you would use for datastores

you have made a pretty good module I must say
good job!

2 Likes

One potential issue I see is if GetData fails (in PlayerDataHandler:Get) the data for the player would be overwritten (if I understand correctly)

Also, in MakeData, I believe a reference to PlayerDataTemplate is returned, potentially leading to the template being modified by whatever calls PlayerDataHandler:Get (often what I do is have PlayerDataTemplate be a function that returns a brand new table every time it is called)

A smaller nitpick, but in MakeData, there is no handling if SaveData fails (this might be able be ignored but I figured I would point it out anyways)