Overview
This module provides enhanced JSON and table manipulation utilities. It extends Roblox’s table and JSON handling with additional functions. Made this for a project and decided to extend it and release it
Source File DataUtils.luau (14.6 KB)
Model File DataUtils.rbxm (7.3 KB)
Features
-
Deep Copy: Create complete independent copies of tables.
-
Merge Tables: Merge two tables with optional deep merge and conflict resolution.
-
Advanced JSON Serialization: Custom type handling for JSON encoding and decoding.
-
Nested Value Handling: Get and set nested table values using dot notation.
-
Table Filtering and Mapping: Filter and transform table values using custom functions.
-
JSON Schema Validation: Validate JSON data against a predefined schema.
-
Data Compression and Encryption: Secure and efficient data storage/transmission methods.
-
Data Diff and Patch: Track changes between data states and apply selective updates.
-
Data Pipeline: Create complex validation and transformation workflows.
-
Data Migration: Manage schema changes and data migrations.
-
Custom Serialization: Serialize and deserialize complex data types.
-
Table Flattening: Convert nested tables to flat key-value pairs and vice versa.
-
Table Comparison: Compare two tables and return a list of differences.
-
Table Sorting: Sort table values based on a custom comparison function.
Installation
To use the DataUtils module, simply require the module in your script:
local DataUtils = require(path.to.DataUtils)
Usage
Deep Copy
Create a deep copy of a table:
local original = { a = 1, b = { c = 2 } }
local copy = DataUtils.DeepCopy(original)
Merge Tables
Merge two tables with optional deep merge and conflict resolution:
local table1 = { a = 1, b = { c = 2 } }
local table2 = { b = { d = 3 }, e = 4 }
local merged = DataUtils.MergeTables(table1, table2, true, true)
Advanced JSON Serialization
Encode and decode JSON with custom type handling:
local data = { position = Vector3.new(1, 2, 3) }
local jsonString = DataUtils.AdvancedEncode(data, { handleSpecialTypes = true })
local decodedData = DataUtils.JSONToTable(jsonString, { convertRobloxTypes = true })
Nested Value Handling
Get and set nested table values using dot notation:
local tbl = { a = { b = { c = 1 } } }
local value = DataUtils.GetNestedValue(tbl, "a.b.c")
DataUtils.SetNestedValue(tbl, "a.b.d", 2)
Data Compression and Encryption
Compress and decompress data:
local data = { a = 1, b = 2 }
local compressed = DataUtils.Compress(data)
local decompressed = DataUtils.Decompress(compressed)
Data Diff and Patch
Create a diff and apply a patch:
local original = { a = 1, b = 2 }
local modified = { a = 1, b = 3, c = 4 }
local diff = DataUtils.CreateDataDiff(original, modified)
local patched = DataUtils.ApplyDataPatch(original, diff)
Data Pipeline
Create and process a data pipeline:
local pipeline = DataUtils.CreateDataPipeline()
:AddValidator(function(data) return true end)
:AddTransformer(function(data) return data end)
local result = pipeline:Process({ a = 1 })
Data Migration
Migrate data with schema changes:
local data = { __version = 1, a = 1 }
local migrations = {
[2] = function(data) data.b = 2 return data end
}
local migratedData = DataUtils.MigrateData(data, migrations)
Exemple Script
local DataUtils = require(script.Parent.DataUtils)
-- Example 1: DeepCopy - Creating Independent Table Copies
local originalTable = {
name = "Player",
stats = {
health = 100,
level = 5
}
}
local copiedTable = DataUtils.DeepCopy(originalTable)
copiedTable.stats.health = 90 -- Modifying the copy doesn't affect the original
-- Example 2: MergeTables - Combining Tables with Advanced Options
local baseConfig = {
graphics = {
resolution = "1080p",
brightness = 50
},
sound = {
volume = 0.7
}
}
local userConfig = {
graphics = {
brightness = 60
},
controls = {
sensitivity = 5
}
}
-- Deep merge with overwrite
local mergedConfig = DataUtils.MergeTables(baseConfig, userConfig, true, true)
-- Example 3: AdvancedEncode - Custom JSON Serialization
local playerData = {
name = "AdventurerX",
position = Vector3.new(10, 20, 30),
inventory = {"sword", "shield", "potion"}
}
local encodedData = DataUtils.AdvancedEncode(playerData, {
handleSpecialTypes = true
})
-- Example 4: GetNestedValue and SetNestedValue - Navigating Complex Tables
local gameState = {
players = {
player1 = {
stats = {
level = 10,
experience = 500
}
}
}
}
-- Retrieve nested value
local playerLevel = DataUtils.GetNestedValue(gameState, "players.player1.stats.level")
-- Set nested value
DataUtils.SetNestedValue(gameState, "players.player1.stats.experience", 750)
-- Example 5: FilterTable - Selective Data Extraction
local items = {
sword = { damage = 20, durability = 80 },
shield = { damage = 0, durability = 90 },
axe = { damage = 15, durability = 70 }
}
-- Filter items with high durability
local robustItems = DataUtils.FilterTable(items, function(item)
return item.durability > 75
end)
-- Example 6: Validation with Schema Checking
local userSchema = {
username = "string",
age = "number",
email = "string"
}
local validUser = {
username = "GamePlayer123",
age = 25,
email = "player@example.com"
}
local isValid, errorMessage = DataUtils.ValidateSchema(validUser, userSchema)
-- Example 7: JSON Conversion with Roblox Types
local vector = Vector3.new(5, 10, 15)
local jsonString = DataUtils.TableToJSON({
position = vector,
timestamp = os.time()
})
local reconstructedData = DataUtils.JSONToTable(jsonString)
-- Example 8: Data Pipeline for Complex Transformations
local dataPipeline = DataUtils.CreateDataPipeline()
dataPipeline
:AddValidator(function(data)
-- Ensure age is positive
return data.age > 0, "Age must be positive"
end)
:AddTransformer(function(data)
-- Normalize username
data.username = data.username:lower()
return data
end)
local processedData = dataPipeline:Process({
username = "PlayerName",
age = 30
})
-- Example 9: Data Diff and Patch
local originalData = {
player = {
name = "Hero",
level = 5
}
}
local modifiedData = {
player = {
name = "Hero",
level = 6,
experience = 1000
}
}
local dataDiff = DataUtils.CreateDataDiff(originalData, modifiedData)
local patchedData = DataUtils.ApplyDataPatch(originalData, dataDiff)
-- Example 10: Compression and Serialization
local sensitiveData = {
apiKey = "secret123",
userCredentials = {
username = "admin"
}
}
local compressedData = DataUtils.Compress(sensitiveData)
local decompressedData = DataUtils.Decompress(compressedData)
--Print everything
print("DeepCopy:")
print(copiedTable)
print("mergedConfig")
print(mergedConfig)
print("encodedData:")
print(encodedData)
print("playerLevel:")
print(playerLevel)
print("robustItems:")
print(robustItems)
print("isValid:")
print(isValid)
print("errorMessage:")
print(errorMessage)
print("jsonString:")
print(jsonString)
print("reconstructedData:")
print(reconstructedData)
print("processedData:")
print(processedData)
print("dataDiff:")
print(dataDiff)
print("patchedData:")
print(patchedData)
print("compressedData:")
print(compressedData)
print("decompressedData:")
print(decompressedData)