Skip to main content

โœ๏ธ Data Operations

This guide covers reading and updating data in Coppermind stores.


๐Ÿ“– Reading Dataโ€‹

Use getData to access the current data:

local data = Coppermind.getData(PlayerSchema, key)

if data then
print("Coins:", data.coins)
print("Level:", data.stats.level)
print("Inventory:", #data.inventory, "items")
end

Return Valuesโ€‹

ScenarioReturnsNotes
Store is readyโœ… Frozen data table
Store is loadingโš ๏ธ nilWarning logged
Store is session locked๐Ÿ”’ nilWarning logged
Store doesn't existโŒ nil

๐ŸงŠ Data Immutabilityโ€‹

Frozen Data

Data returned by getData is frozen and cannot be modified!

local data = Coppermind.getData(PlayerSchema, key)

-- โŒ This will error!
data.coins = 100 -- Cannot modify frozen table

-- โœ… Use updateData instead
Coppermind.updateData(PlayerSchema, key, function(data)
data.coins = 100
return nil
end)

This immutability ensures data integrity and prevents accidental modifications.


โœ๏ธ Updating Dataโ€‹

Use updateData to safely modify data:

local success = Coppermind.updateData(PlayerSchema, key, function(data)
-- Modify the mutable copy
data.coins += 100
return nil
end)

if success then
print("Data updated!")
end

Modify the data directly and return nil:

Coppermind.updateData(PlayerSchema, key, function(data)
data.coins += 100
data.gems += 50
data.stats.xp += 25
table.insert(data.inventory, "new_item")
return nil -- Apply mutations
end)

โŒ When Updates Failโ€‹

updateData returns false when:

ReasonDescription
Store doesn't existKey was never loaded
Store is loadingData not ready yet
Store is session lockedAnother server owns it
Invalid stateStore is unloading/unloaded
No dataStore has nil data
local success = Coppermind.updateData(PlayerSchema, key, function(data)
data.coins += 100
return nil
end)

if not success then
warn("Failed to update data for", key)
end

๐Ÿ”— Working with Nested Dataโ€‹

Reading Nested Valuesโ€‹

local data = Coppermind.getData(PlayerSchema, key)

-- Access nested tables
local level = data.stats.level
local musicVolume = data.settings.audio.musicVolume

-- Safely access potentially nil nested values
local achievementProgress = data.achievements and data.achievements.progress

Updating Nested Valuesโ€‹

Coppermind.updateData(PlayerSchema, key, function(data)
-- Update nested values
data.stats.level += 1
data.stats.xp = 0

-- Modify nested arrays
table.insert(data.inventory, "reward_item")

-- Update deeply nested values
data.settings.audio.musicVolume = 0.5

return nil
end)

๐Ÿ“ฆ Working with Arraysโ€‹

Coppermind.updateData(PlayerSchema, key, function(data)
table.insert(data.inventory, "sword")
table.insert(data.inventory, "shield")
return nil
end)

๐ŸŽฏ Common Patternsโ€‹

๐Ÿ’ฐ Increment/Decrementโ€‹

local function addCoins(key: string, amount: number)
return Coppermind.updateData(PlayerSchema, key, function(data)
data.coins += amount
return nil
end)
end

local function spendCoins(key: string, amount: number): boolean
local success = false

Coppermind.updateData(PlayerSchema, key, function(data)
if data.coins >= amount then
data.coins -= amount
success = true
end
return nil
end)

return success
end

๐Ÿ”€ Toggle Valuesโ€‹

local function toggleSetting(key: string, setting: string)
Coppermind.updateData(PlayerSchema, key, function(data)
data.settings[setting] = not data.settings[setting]
return nil
end)
end

โฌ†๏ธ Conditional Updatesโ€‹

local function levelUp(key: string): boolean
local leveled = false

Coppermind.updateData(PlayerSchema, key, function(data)
local xpNeeded = data.stats.level * 100

if data.stats.xp >= xpNeeded then
data.stats.level += 1
data.stats.xp -= xpNeeded
leveled = true
end

return nil
end)

return leveled
end

๐ŸŽ Batch Updatesโ€‹

local function claimRewards(key: string, rewards: { coins: number, items: { string } })
Coppermind.updateData(PlayerSchema, key, function(data)
data.coins += rewards.coins

for _, item in rewards.items do
table.insert(data.inventory, item)
end

return nil
end)
end

โœ… Best Practicesโ€‹

1. Keep Updates Atomicโ€‹

Single Update

Do all related changes in a single updateData call!

-- โœ… Good - single atomic update
Coppermind.updateData(PlayerSchema, key, function(data)
data.coins -= 100
table.insert(data.inventory, "purchased_item")
return nil
end)

-- โŒ Avoid - multiple separate updates
Coppermind.updateData(PlayerSchema, key, function(data)
data.coins -= 100
return nil
end)
Coppermind.updateData(PlayerSchema, key, function(data)
table.insert(data.inventory, "purchased_item")
return nil
end)

2. Validate Before Writingโ€‹

local function purchaseItem(key: string, itemId: string, cost: number): (boolean, string?)
local result = { success = false, error = nil }

Coppermind.updateData(PlayerSchema, key, function(data)
if data.coins < cost then
result.error = "Not enough coins"
return nil
end

if table.find(data.inventory, itemId) then
result.error = "Already owned"
return nil
end

data.coins -= cost
table.insert(data.inventory, itemId)
result.success = true
return nil
end)

return result.success, result.error
end

3. Handle Missing Data Gracefullyโ€‹

local function safeGetCoins(key: string): number?
local data = Coppermind.getData(PlayerSchema, key)

if not data then
return nil
end

return data.coins
end