Skip to content
Engine

Data

Patch

Read and write deep paths in nested tables, fill templates, and check that data can be saved to a DataStore.

PackageShared

Getting it

local Patch = Engine:GetPackage("Patch")

Overview

Patch works with paths into nested tables. A path is either a dot string such as "Inventory.Weapons.1" (number segments become number keys) or an array of keys such as { "Inventory", "Weapons", 1 }. Unlike TableKit, Patch writes in place, which is what you want when you own the data, such as a player's profile.

local Patch = Engine:GetPackage("Patch")

local data = { Inventory = { Weapons = { "Sword" } } }

local keys = Patch.Parse("Inventory.Weapons")
Patch.Insert(data, keys, nil, "Bow")              -- { "Sword", "Bow" }
Patch.Set(data, { "Stats" }, {})                  -- every table on a path must exist
Patch.Set(data, Patch.Parse("Stats.Kills"), 3)    -- the last key may be new
print(Patch.Get(data, Patch.Parse("Stats.Kills"))) --> 3

local ok, reason, where = Patch.Validate(data)

Paths

Parse

Patch.Parse(path: Path): Keys

Turns a path into an array of keys. Errors on an empty path.

Format

Patch.Format(keys: Keys): string

Turns keys back into a dot string, for messages and logging.

IsPrefix

Patch.IsPrefix(prefix: Keys, keys: Keys): boolean

Whether keys starts with prefix, for example to check whether a change at keys falls inside a watched branch.

Reading and writing

Get

Patch.Get(root: table, keys: Keys, count: number?): any

The value at the path, or nil if any step is missing. With count, follows only the first count keys.

Set

Patch.Set(root: table, keys: Keys, value: any): any

Sets the value at the path and returns the previous value. Every table on the path must already exist; only the last key may be new. When a step is missing or is not a table, Set errors with that part of the path (Engine: Patch - Stats does not exist, Engine: Patch - Coins is not a table) and changes nothing.

Insert

Patch.Insert(root: table, keys: Keys, index: number?, value: any): number

Inserts into the array at the path, at index or at the end. Returns the index used. Errors if the path is not an array.

Remove

Patch.Remove(root: table, keys: Keys, index: number): any

Removes and returns the item at index of the array at the path.

Fill

Patch.Fill(target: table, template: table)

Adds every string key from template that target does not have, deep-copying tables, and recurses into tables both have. Existing values are never overwritten.

Validation

Validate

Patch.Validate(value: any): (boolean, string?, string?)

Checks that a value can be stored in a DataStore. Returns true, or false with the reason and the path of the first problem ("<root>" for the value itself).

It rejects:

  • functions, Instances, Vector3s and every other non-plain type (strings, booleans, numbers, buffers and tables are allowed);
  • NaN and infinite numbers;
  • keys that are not strings or positive whole numbers;
  • tables that mix array and dictionary keys;
  • arrays with gaps;
  • nesting deeper than 32 levels.
local ok, reason, where = Patch.Validate({ Position = Vector3.zero })
-- false, "Vector3 values cannot be stored", "Position"

Types

export type Path = string | { any }
export type Keys = { any }