Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Do tables carry their metatables to DataStores?

I'm trying to create a messenger GUI that uses DataStores to get data across servers. I'm currently working on actually creating the DataStore, as well as giving it a bit more functionality, like giving it a key index and a way to monitor what happens to it.

datastore = game:GetService("DataStoreService"):GetDataStore("MessengerData")

Info log:

infolog = datastore:GetAsync("INFO_LOG")

if infolog == nil then
	infolog = {}
	setmetatable(infolog, {
		__newindex = function(self, key, value)
			rawset(self, key, value)
			datastore:SetAsync("INFO_LOG", self)
		end
	})
	datastore:SetAsync("INFO_LOG", infolog)
end

Key index:

index = datastore:GetAsync("KEY_INDEX")

if index == nil then
	print("Initializing MessengerData KEY_INDEX for the first time...")
	index = {}
	setmetatable(index, {
		__newindex = function(self, key, value)
			rawset(self, key, value)
			datastore:SetAsync("KEY_INDEX", self)
		end
	})
	datastore:SetAsync("KEY_INDEX", index)
	print("Initialized.")
	table.insert(infolog, "Initialized KEY_INDEX at "..os.time())
end

And then I could just iterate over INFO_LOG to see what's been going on, and KEY_INDEX to see who's in the DataStore. I put a metatable on the index and the info log because I figured that every time I appended to those tables, I'd save them to their DataStore keys. Since I've saved a table with a metatable to the DataStore, would this shortcut apply to other scripts like this?

datastore = game:GetService("DataStoreService"):GetDataStore("MessengerData")
index = datastore:GetAsync("KEY_INDEX")
index.Bob = true
--Assuming the metatable is still there, I wouldn't have to put the SetAsync line here, right?

1 answer

✓ Accepted answer

Actually, no, they don't. However, we always have the alternative of making some kind of custom "GetAsync" method, that returns an invoked table with a new setmetatable. Here's an example:

-- Get the data store service
local MyDataStore = game:GetService("DataStoreService"):GetDataStore("Metatables")

-- Set "MyTable" to an empty table
MyDataStore:SetAsync("MyTable",{})

-- Make a blank table we can use to get modified information from
local DataUtility = {}

-- The metatable we return to a table with our new GetAsync fucntion
local Metatable = {
	__index = function(tab, key)
		print('Could not find: '..key..' in table: '..tostring(tab))
		return 'Not found'
	end
}

-- Make a custom GetAsync especially for tables and metatables
function DataUtility:GetMetaAsync(Datastore, Key)

	-- Use regular GetAsync to see if our request exists...
	local Past = Datastore:GetAsync(Key)

	-- If it does, and it's a table, then...
	if Past and type(Past) == 'table' then

		-- Return the table, while also giving it the assigned metatable.
		return setmetatable(Past,Metatable)

	else

		-- If the old key isn't found, do this..
		print(tostring(Key)..' was not found, or is not a table.')
	end
end

-- Print the result using our new function, and index it for "Testing" (which will obviously be nil)

print(DataUtility:GetMetaAsync(MyDataStore, "MyTable").Testing)

-- This should print "Not found", because that's what our index metamethod returns.

Didn't mean to reply to this question with just a script, i tried explaining as much as possible as i went. But you seem like you know enough to know what's going on anyway, so i hope this helped.

This discussion is preserved as it was. New answers, comments, and votes are closed.