Srlion/goobie-sql
Srlion/goobie-sql has 27 GitHub stars and 3 forks. GitHot measured 0 in 7 days. Last checked 2026-11-02 11:29 UTC. Last push 2026-08-13.
What you can do
- ✅ Dual Database Support - MySQL and SQLite
- ⚡ Async & Sync - Both asynchronous and synchronous queries
- 🔄 Easy Transactions - Simple transaction handling with coroutines
- 📊 Migration System - Built-in database migrations
Progression mesurée des étoiles
- in 24h
- Mise à jour retardée
- in 7 days
- 0
- in 15 days
- Mise à jour retardée
- in 1 month
- Mise à jour retardée
Variations nettes sur des périodes qui se chevauchent, pas des totaux quotidiens. Les mesures absentes restent vides. Les étoiles indiquent l’intérêt, pas la qualité.
À propos
Easily connect to MySQL in Garry's Mod using Rust binary!
DonnéesREADME.md
OriginalGoobie SQL
A simple, lightweight, and fast MySQL/SQLite library for Garry's Mod.
⚠️ Note: The latest version requires the next Garry's Mod update (available on dev/x86-64 branch).
📋 Table of Contents
🚀 Features
- ✅ Dual Database Support - MySQL and SQLite
- ⚡ Async & Sync - Both asynchronous and synchronous queries
- 🔄 Easy Transactions - Simple transaction handling with coroutines
- 📊 Migration System - Built-in database migrations
- 📦 Single File - One-file library for easy integration
📦 Installation
Download the latest
goobie-sql.luafrom GitHub ReleasesFor MySQL users: Also download
gmsv_goobie_mysql_x_x_x.dlland extract to:garrysmod/lua/bin/gmsv_goobie_mysql_x_x_x.dllAdd
goobie-sql.luato your addon'sthirdpartyfolder
🛠️ Quick Setup
SQLite (Recommended for beginners)
local goobie_sql = include("myaddon/thirdparty/goobie-sql.lua")
local conn = goobie_sql.NewConn({
driver = "sqlite",
})
MySQL
local goobie_sql = include("myaddon/thirdparty/goobie-sql.lua")
local conn = goobie_sql.NewConn({
driver = "mysql",
uri = "mysql://USERNAME:PASSWORD@HOST/DATABASE",
})
📚 API Reference
Connection Setup
goobie_sql.NewConn(options)
Creates and starts a connection automatically. For async initialization, pass a callback as the second argument.
Parameters:
options(table) - Connection configuration options
Example:
local conn = goobie_sql.NewConn({
driver = "mysql", -- "mysql" or "sqlite"
-- Error handling callback
on_error = function(err, trace)
print("Database error:", err)
end,
-- MySQL Options (choose URI or individual options)
uri = "mysql://user:pass@host:port/db", -- Recommended
-- OR
host = "127.0.0.1",
port = 3306,
username = "root",
password = "password",
database = "mydb",
-- Additional MySQL settings
charset = "utf8mb4",
collation = "utf8mb4_unicode_ci",
timezone = "UTC",
statement_cache_capacity = 100,
socket = "/tmp/mysql.sock",
})
Connection Management
| Method | Description | Returns |
|---|---|---|
Conn:Start(callback) |
Connect asynchronously | - |
Conn:StartSync() |
Connect synchronously | throws on error |
Conn:Disconnect(callback) |
Disconnect asynchronously | - |
Conn:DisconnectSync() |
Disconnect synchronously | err |
Conn:State() |
Get connection state | number |
Conn:StateName() |
Get connection state name | string |
Conn:ID() |
Get connection ID | number |
Conn:Host() |
Get host | string |
Conn:Port() |
Get port | number |
Conn:Ping(callback) |
Ping database async | - |
Conn:PingSync() |
Ping database sync | err, latency |
Query Methods
| Method | Type | Description | Returns |
|---|---|---|---|
Conn:Run(query, opts) |
Async | Execute query (no result) | - |
Conn:RunSync(query, opts) |
Sync | Execute query (no result) | err |
Conn:Execute(query, opts) |
Async | Execute with metadata | - |
Conn:ExecuteSync(query, opts) |
Sync | Execute with metadata | err, result |
Conn:Fetch(query, opts) |
Async | Fetch multiple rows | - |
Conn:FetchSync(query, opts) |
Sync | Fetch multiple rows | err, rows |
Conn:FetchOne(query, opts) |
Async | Fetch single row | - |
Conn:FetchOneSync(query, opts) |
Sync | Fetch single row | err, row |
Conn:UpsertQuery(table, opts) |
Async | Insert or update | - |
Conn:UpsertQuerySync(table, opts) |
Sync | Insert or update | err, result |
Query Options
{
params = {"value1", "value2"}, -- Parameters for placeholders {1}, {2}
callback = function(err, res) end, -- Async callback
raw = false -- Set true for multi-statement queries (no params)
}
Transactions
Use Begin() or BeginSync() for database transactions. Inside transactions, queries return results directly (no callbacks).
-- Async transaction
conn:Begin(function(err, txn)
if err then return end
local err, res = txn:Execute("INSERT INTO users (name) VALUES ('John')")
if err then
txn:Rollback() -- Must rollback explicitly on error
return
end
local err = txn:Commit()
print("Transaction complete, open:", txn:IsOpen()) -- false
end)
-- Sync transaction
local err, txn = conn:BeginSync()
if not err then
local err, res = txn:Execute("INSERT INTO users (name) VALUES ('Jane')")
if err then
txn:Rollback()
else
txn:Commit()
end
end
Migrations
Run database migrations with version tracking:
local conn = goobie_sql.NewConn({
driver = "sqlite",
addon_name = "my_addon", -- Required for migration tracking
})
local current_version, first_run = conn:RunMigrations({
-- Migration 1: String format
{
UP = [[
CREATE TABLE users (
id {CROSS_PRIMARY_AUTO_INCREMENTED},
name TEXT NOT NULL,
created_at {CROSS_OS_TIME_TYPE}
);
]],
DOWN = "DROP TABLE users;"
},
-- Migration 2: Function format
{
UP = function(process, conn)
process("ALTER TABLE users ADD COLUMN email TEXT;")
end,
DOWN = function(process, conn)
process("ALTER TABLE users DROP COLUMN email;")
end
}
})
print("Database version:", current_version, "First run:", first_run)
Conditional Migrations
{
UP = [[
CREATE TABLE test (
--@ifdef SQLITE
id INTEGER PRIMARY KEY,
--@else
id BIGINT AUTO_INCREMENT PRIMARY KEY,
--@endif
name TEXT
);
]]
}
Cross Syntaxes
Write database-agnostic queries using cross-syntax placeholders:
| Placeholder | SQLite | MySQL |
|---|---|---|
{CROSS_NOW} |
(CAST(strftime('%s', 'now') AS INTEGER)) |
(UNIX_TIMESTAMP()) |
{CROSS_PRIMARY_AUTO_INCREMENTED} |
INTEGER PRIMARY KEY |
BIGINT AUTO_INCREMENT PRIMARY KEY |
{CROSS_COLLATE_BINARY} |
COLLATE BINARY |
BINARY |
{CROSS_CURRENT_DATE} |
DATE('now') |
CURDATE() |
{CROSS_OS_TIME_TYPE} |
INT UNSIGNED NOT NULL DEFAULT (...) |
INT UNSIGNED NOT NULL DEFAULT (...) |
{CROSS_INT_TYPE} |
INTEGER |
BIGINT |
{CROSS_JSON_TYPE} |
TEXT |
JSON |
Example:
conn:RunSync([[
SELECT * FROM users WHERE created_at > {CROSS_NOW}
]])
🔧 Configuration Options
Error Object Structure
{
message = "Error description",
code = 1234, -- MySQL error code (optional)
sqlstate = "42000" -- SQL state code (optional)
}
-- Has __tostring metamethod for easy printing
UpsertQuery Options
local opts = {
primary_keys = {"id"}, -- Unique/primary keys that could conflict
inserts = { -- Values to insert
id = 1,
name = "John",
email = "[email protected]"
},
updates = {"name", "email"}, -- Columns to update on conflict
binary_columns = {"data"}, -- Binary columns (SQLite specific)
callback = function(err, res) end -- Async callback
}
conn:UpsertQuery("users", opts)
-- OR
local err, res = conn:UpsertQuerySync("users", opts)
📄 Examples
Basic Query Examples
-- Simple insert
conn:Execute("INSERT INTO users (name) VALUES ({1})", {
params = {"Alice"},
callback = function(err, res)
if err then
print("Error:", err)
else
print("Inserted ID:", res.last_insert_id)
print("Rows affected:", res.rows_affected)
end
end
})
-- Fetch multiple rows
conn:Fetch("SELECT * FROM users WHERE age > {1}", {
params = {18},
callback = function(err, rows)
if not err then
for i, row in ipairs(rows) do
print("User:", row.name, "Age:", row.age)
end
end
end
})
-- Fetch single row
conn:FetchOne("SELECT * FROM users WHERE id = {1}", {
params = {1},
callback = function(err, user)
if not err and user then
print("Found user:", user.name)
end
end
})
Synchronous Examples
-- Synchronous queries (easier for simple operations)
local err = conn:RunSync("DELETE FROM users WHERE inactive = 1")
if err then
print("Delete failed:", err)
end
local err, users = conn:FetchSync("SELECT * FROM users LIMIT 10")
if not err then
print("Found", #users, "users")
end
Advanced Transaction Example
conn:Begin(function(err, txn)
if err then return end
-- Transfer money between accounts
local err, sender = txn:FetchOne("SELECT balance FROM accounts WHERE id = {1}", {
params = {sender_id}
})
if err or not sender or sender.balance < amount then
txn:Rollback()
return
end
-- Deduct from sender
local err = txn:Execute("UPDATE accounts SET balance = balance - {1} WHERE id = {2}", {
params = {amount, sender_id}
})
if err then
txn:Rollback()
return
end
-- Add to receiver
local err = txn:Execute("UPDATE accounts SET balance = balance + {1} WHERE id = {2}", {
params = {amount, receiver_id}
})
if err then
txn:Rollback()
return
end
-- Commit transaction
local err = txn:Commit()
if not err then
print("Transfer completed successfully!")
end
end)
Complete Setup Example
-- Complete example with error handling and migrations
local goobie_sql = include("myaddon/thirdparty/goobie-sql.lua")
local conn = goobie_sql.NewConn({
driver = "mysql",
uri = "mysql://user:pass@localhost/gamedb",
addon_name = "my_gamemode",
on_error = function(err, trace)
print("[DB Error]", err.message)
if err.code then
print("Error code:", err.code)
end
end
})
-- Run migrations
local version, first_run = conn:RunMigrations({
{
UP = [[
CREATE TABLE players (
steam_id VARCHAR(32) PRIMARY KEY,
name VARCHAR(64) NOT NULL,
playtime {CROSS_INT_TYPE} DEFAULT 0,
created_at {CROSS_OS_TIME_TYPE}
);
]],
DOWN = "DROP TABLE players;"
},
{
UP = "ALTER TABLE players ADD COLUMN last_seen {CROSS_OS_TIME_TYPE};",
DOWN = "ALTER TABLE players DROP COLUMN last_seen;"
}
})
if first_run then
print("Database initialized for the first time!")
else
print("Database updated to version", version)
end
-- Use the connection
conn:UpsertQuery("players", {
primary_keys = {"steam_id"},
inserts = {
steam_id = "STEAM_1:0:123456",
name = "PlayerName",
playtime = 0
},
updates = {"name", "last_seen"}
})
📞 Support
- Documentation: MySQL URI Format
- Issues: GitHub Issues
- Releases: GitHub Releases
💡 Pro Tip: Ping connections sparingly! Check this article on why frequent connection pinging can be harmful.
Explorer des projets similaires
Asabeneh/30-Days-Of-Python
Le défi de programmation 30 Days of Python est un guide pas à pas pour apprendre le langage de programmation Python en 30 jours. Ce défi peut prendre plus de 100 jours. Avancez à votre rythme. Ces vidéos peuvent aussi vous aider : https://www.youtube.com/channel/UC7PNRuno1rzYPb1xLa4yktw
78,696 étoilesgrafana/grafana
Plateforme ouverte et composable d’observabilité et de visualisation de données. Visualise les métriques, les journaux et les traces issus de plusieurs sources, comme Prometheus, Loki, Elasticsearch, InfluxDB, Postgres et bien d’autres.
77,876 étoilesredis/redis
Pour les développeurs qui créent des applications en temps réel pilotées par les données, Redis est le cache, le serveur de structures de données et le moteur de requêtes documentaires et vectorielles préféré, le plus rapide et le plus riche en fonctionnalités.
77,489 étoilesapache/superset
Apache Superset est une plateforme de visualisation et d'exploration de données.
75,515 étoiles