TableManager
A class for managing a table such that you can listen to changes and modify values easily. TableManager is designed to provide robust listener functionality at the cost of some performance.
tip
The TableManager has some methods to combine functionality for both values and arrays. It will redirect to the proper method depending on your given arguments.
:Set() -- Redirects to :SetValue() or :ArraySet()
:Increment() -- Redirects to :IncrementValue() or :ArrayIncrement()
:Mutate() -- Redirects to :MutateValue() or :ArrayMutate()
Types
CanBeArray<T>
A type that could be an individual of the type or an array of the type.
Path
type
Path =
string
|
{
any
}
A path to a value in a table. Can be written as a string in dot format or an array of strings. :::Note The array format is faster to parse and should be used when possible. :::
local tbl = {
MyPath = {
To = {
Value = 0;
};
};
}
local path1: Path = "MyPath.To.Value" -- Style 1
local path2: Path = {"MyPath", "To", "Value"} -- Style 2
ValueListenerFn
ListenerType
type
ListenerType =
"ValueChanged"
|
"ArraySet"
|
"ArrayInsert"
|
"ArrayRemove"
This information is mostly for internal use.
DataChangeSource
type
DataChangeSource =
"self"
|
"child"
|
"parent"
This information is mostly for internal use.
ChangeMetadata
interface
ChangeMetadata {
SourcePath:
{
string
}
--
The origin path of the change.
NewValue:
any?
--
[Only for value changes] The new value.
OldValue:
any?
--
[Only for value changes] The old value.
}
Metadata about the change that fired a listener. Used to provide more context to listeners. Allows you to figure out where the change came from, if it wasnt a direct change.
Properties
Enums
TableManager.Enums:
{
ListenerType:
ListenerTypeEnum
,
DataChangeSource:
DataChangeSourceEnum
}
A collection of enums used by the TableManager.
Functions
new
ConstructorCreates a new TableManager. Takes a table to manage, if one is not given then it will construct an empty table.
Modifying the given table
Once you give a table to a TableManager
, you should never modify it directly.
Doing so can result in the TableManager
being unable to properly track changes
and potentially cause data desyncs.
Key/Value Rules
The given table's keys should follow these rules:
- No Mixed Tables (Tables containing keys of different datatypes)
- Avoid using tables as keys.
- Keys must not contain periods.
- Keys must not be empty strings.
- Tables/Arrays should be assigned to only one key. (No shared references as this can cause desyncs)
- Nested tables/arrays should not be given to other
TableManager
instances. (Can cause desyncs)
info
Only one TableManager
should be created for a given table. Attempting to create a TableManager
for a table
that is already being managed will return the existing TableManager
.
Call metamethod
You can call the TableManager
class to create a new instance of it.
TableManager()
is equivalent to TableManager.new()
.
local tbl = {
Coins = 0;
Inventory = {
"Sword";
"Shield";
};
}
local tblMngr = TableManager.new(tbl)
tblMngr:SetValue("Coins", 100)
tblMngr:IncrementValue("Coins", 55)
print(tblMngr:Get("Coins")) -- 155
tblMngr:ArrayInsert("Inventory", "Potion")
tblMngr:ArrayInsert("Inventory", 2, "Bow")
print(tblMngr:Get("Inventory")) -- {"Sword", "Bow", "Shield", "Potion"}
Destroy
TableManager:
Destroy
(
) →
(
)
Disconnects any listeners and removes the table from the managed tables.
Set
Sets the value at the given path to the given value. :Set acts as a combined function for :SetValue and :ArraySet.
:Set(myPathToValue, newValue)
:Set(myPathToArray, index, newValue)
Overwriting the root table
Overwriting the root table is not recommended, but is technically possible by giving
an empty table or string as a Path
. Doing so has not been tested in depth and may
result in unintended behavior.
Setting array values
You cannot set values to nil in an array with this method due to the way it parses args.
Use ArraySet
instead if you need to set values to nil.
Increment
Increments the value at the given path by the given amount. If the value is not a number, it will throw an error. :Increment acts as a combined function for :IncrementValue and :ArrayIncrement.
:Increment(myPathToValue, amountToIncrementBy)
:Increment(myPathToArray, index, amountToIncrementBy)
Mutate
Mutates the value at the given path by calling the given function with the current value.
:Mutate(myPathToValue, function(currentValue)
return currentValue + 1
end)
SetValue
Sets the value at the given path to the given value. This will fire the ValueChanged signal if the value is different. Returns a boolean indicating whether or not the value was changed.
local didChange = manager:SetValue("MyPath.To.Value", 100)
IncrementValue
Increments the value at the given path by the given amount. If the value at the path or the given amount is not a number, it will throw an error. Returns the newly incremeneted value.
local newValue = manager:IncrementValue("MyPath.To.Value", 100)
MutateValue
Mutates the value at the given path by calling the given function with the current value. The function should return the new value.
manager:SetValue("MyPath.To.Value", "Hello World")
local newValue = manager:MutateValue("MyPath.To.Value", function(currentValue)
return string.upper(currentValue) .. "!"
end)
print(newValue) -- HELLO WORLD!
print(manager:GetValue("MyPath.To.Value")) -- HELLO WORLD!
SetManyValues
Sets the values at the given path to the given values. This will fire the ValueChanged listener for each value that is different.
caution
Uses pairs to check through the given table and thus Does not support setting values to nil.
local manager = TableManager.new({
Foo = {
Bar = {
Value1 = 0;
Value2 = 0;
Value3 = 0;
};
};
})
manager:SetManyValues("Foo.Bar", {
Value1 = 100;
Value3 = 300;
})
ArrayMutate
TableManager:
ArrayMutate
(
index:
number
|
{
number
}
|
"#"
,
--
The index or indices to mutate. If "#" is given, it will mutate all indices.
fn:
(
currentValue:
any
)
→
(
any
)
--
The function to call with the current value. Should return the new value.
) →
(
)
Mutates an index or indices in the array at the given path by calling the given function with the current value.
manager:SetValue("MyArray", {1, 2, 3, 4, 5})
manager:ArrayMutate("MyArray", 3, function(currentValue)
return currentValue * 2
})
print(manager:GetValue("MyArray")) -- {1, 2, 6, 4, 5}
ArrayIncrement
TableManager:
ArrayIncrement
(
index:
number
|
{
number
}
,
--
The index or indices to increment.
amount:
number?
--
The amount to increment by. If not given, it will increment by 1.
) →
(
)
Increments the indices at the given path by the given amount.
manager:SetValue("MyArray", {1, 2, 3, 4, 5})
manager:ArrayIncrement("MyArray", 3, 10)
print(manager:GetValue("MyArray")) -- {1, 2, 13, 4, 5}
ArraySet
Sets the value at the given index in the array at the given path. The index can be a number or an array of numbers. If an array is given then the value will be set at each of those indices in the array.
ArrayInsert
Inserts the given value into the array at the given path at the given index.
If no index is given, it will insert at the end of the array.
This follows the convention of table.insert
where the index is given in the middle
only if there are 3 args.
x:ArrayInsert("MyArray", "Hello") -- Inserts "Hello" at the end of the array
x:ArrayInsert("MyArray", 1, "Hello") -- Inserts "Hello" at index 1
x:ArrayInsert("MyArray", 1) -- appends 1 to the end of the array
x:ArrayInsert("MyArray", 1, 2) -- Inserts 2 at index 1
ArrayRemove
Removes the value at the given index from the array at the given path. If no index is given, it will remove the last value in the array. Returns the value that was removed if one was.
ArrayRemoveFirstValue
Removes the first instance of the given value from the array at the given path. Returns a number indicating the index that it was was removed from if one was.
Get
Fetches the value at the given path.
Accepts a string path or an array path.
Accepts an optional secondary argument to fetch a value at an index in an array.
Aliases: GetValue
local manager = TableManager.new({
Currency = {
Coins = 100;
Gems = 10;
};
})
-- The following are all equivalent acceptable methods of fetching the value.
print(manager:Get("Currency.Coins")) -- 100
print(manager:Get({"Currency", "Coins"})) -- 100
print(manager:Get().Currency.Coins) -- 100
Getting the Root Table
Calling :Get()
with no arguments, an empty string,
or an empty table will return the root table.
ToTableState
Returns a TableState Object for the given path.
warning
This method is not feature complete and does not work for all edge cases and should be used with caution.
local path = "MyPath.To.Value"
local state = manager:ToTableState(path)
state:Set(100)
manager:Increment(path, 50)
state:Increment(25)
print(state:Get()) -- 175
ToFusionState
Returns a Fusion State object that is bound to the value at the given path. This method is memoized so calling it repeatedly with the same path will return the same State object and quickly.
Deffered Signals
The value of the Fusion State object is updated via the ValueChanged listener and thus may be deffered if your signals are deffered.
Setting
Although this currently returns a Fusion Value object, it is not recommended to set the value as this may be a Computed in the future. Setting the state will not actually change the value in the TableManager.
local path = "MyPath.To.Value"
manager:SetValue(path, 100)
local state = manager:ToFusionState(path)
print(peek(state)) -- 100
manager:SetValue(path, 200)
task.wait() -- If your signals are deffered then the state will update on the next frame
print(peek(state)) -- 200
PromiseValue
Creates a promise that resolves when the given condition is met. The condition is immediately and every time the value changes. If no condition is given then it will resolve with the current value unless it is nil, in which case it will resolve on the first change.
Observe
TableManager:
Observe
(
runOnNil:
boolean?
--
Whether or not to fire the function when the value is nil.
) →
Connection
--
A connection used to disconnect the listener.
Observes a value at a path and calls the function immediately with the current value, as well as when it changes.
Listening to nil values
It will NOT fire if the new/starting value is nil, unless runOnNil is true. When it changes from nil, the oldValue will be the last known non nil value. The binding call of the function is an exception and will give nil as the oldValue. This is done so that Observe can be used to execute instructions when a value is percieved as 'ready'.
local path = "MyPath.To.Value"
local connection = manager:Observe(path, function(newValue)
print("Value at", path, "is", newValue)
end)
connection() -- Disconnects the listener
ListenToKeyChange
TableManager:
ListenToKeyChange
(
fn:
(
keyChanged:
any
,
newValue:
any
,
oldValue:
any
)
→
(
)
) →
(
)
Listens to a change at a specified path and calls the function when the value changes.
manager:Set("Stats", {
Health = 100;
Mana = 50;
})
local connection = manager:ListenToKeyChange("Stats", function(key, newValue)
print(`{key} changed to {newValue}`)
end)
manager:SetValue("Stats.Health", 200) -- Health changed to 200
manager:SetValue("Stats.Mana", 100) -- Mana changed to 100
ListenToKeyAdd
Listens to when a new key is added (Changed from nil) to a table at a specified path and calls the function.
ListenToKeyRemove
Listens to when a key is removed (Set to nil) from a table at a specified path and calls the function.
ListenToValueChange
Listens to a change at a specified path and calls the function when the value changes. This does NOT fire when the value is an array/dictionary and one of its children changes.
local connection = manager:ListenToValueChange("MyPath.To.Value", function(newValue, oldValue)
print("Value changed from", oldValue, "to", newValue)
end)
connection() -- Disconnects the listener
ListenToArraySet
Listens to when an index is set in an array at a specified path and calls the function. The function receives the index and the new value.
caution
The array listeners do not fire from changes to parent or child values.
ListenToArrayInsert
Listens to when a value is inserted into an array at a specified path and calls the function when the value changes.
ListenToArrayRemove
Listens to when a value is removed from an array at a specified path and calls the function.