Persistent Data#
HELIX provides a built-in SQLite database system for persistent data storage. This is ideal for tracking progress, saving custom settings, or keeping game state across sessions. The Database class provides both synchronous and asynchronous operations for maximum flexibility.
🔧 Initialization#
Before using the database, you must initialize it with a file path:
- The database file will be created in the project's saved directory if it doesn't exist
- You only need to call this once on the server, typically at startup
Example
Database.Initialize("my_game_data.db")
📝 Executing Commands#
For non-SELECT operations (INSERT, UPDATE, DELETE, CREATE TABLE), use:
Example
Database.Execute(query, params)
queryis your SQL statement as a stringparamsis an optional array of parameters for prepared statements- Returns
trueon success,falseon failure
Example
-- Create a table
Database.Execute("CREATE TABLE IF NOT EXISTS players (id INTEGER PRIMARY KEY, name TEXT, level INTEGER)")
-- Insert data
Database.Execute("INSERT INTO players (name, level) VALUES (?, ?)", {"Nova", 12})
-- Update data
Database.Execute("UPDATE players SET level = ? WHERE name = ?", {15, "Nova"})
📥 Querying Data#
To retrieve data with SELECT queries, use:
Example
local results = Database.Select(query, params)
This returns an array of rows, where each row has a .Columns property:
Example
local players = Database.Select("SELECT name, level FROM players WHERE level > ?", {10})
for _, row in ipairs(players) do
print("Player:", row.Columns.name, "Level:", row.Columns.level)
end
⚡ Async Operations#
For better performance, especially with large operations, use the async versions:
Example
-- Async execute
Database.ExecuteAsync("INSERT INTO players (name, level) VALUES (?, ?)", {"Storm", 8}, function(success)
if success then
print("Player added successfully")
else
print("Failed to add player")
end
end)
-- Async select
Database.SelectAsync("SELECT * FROM players", {}, function(results)
print("Found", #results, "players")
for _, row in ipairs(results) do
print(row.Columns.name)
end
end)
🔐 Best Practices#
- Always initialize the database before use
- Use prepared statements with parameters to prevent SQL injection
- Handle potential failures by checking return values or callback parameters
- Consider using async operations for large datasets to avoid blocking the main thread
- Always check if results exist before accessing them
Summary#
Database.Initialize(path)sets up the database fileDatabase.Execute(query, params)runs non-SELECT commands synchronouslyDatabase.Select(query, params)retrieves data synchronouslyDatabase.ExecuteAsync()andDatabase.SelectAsync()provide non-blocking alternatives- All operations support parameterized queries for security
The Database class gives you full SQL power for complex data relationships, queries, and persistent storage needs.