https://github.com/srlion/goobie-mysql
Easily connect to MySQL in Garry's Mod using Rust binary!
https://github.com/srlion/goobie-mysql
async binary fast garrysmod gmod gmod-mysql graceful graceful-shutdown mysql rust rust-lang rustlang simple sql transactions
Last synced: about 2 months ago
JSON representation
Easily connect to MySQL in Garry's Mod using Rust binary!
- Host: GitHub
- URL: https://github.com/srlion/goobie-mysql
- Owner: Srlion
- Created: 2024-10-06T09:35:08.000Z (7 months ago)
- Default Branch: master
- Last Pushed: 2025-03-06T09:59:02.000Z (about 2 months ago)
- Last Synced: 2025-03-06T10:23:10.349Z (about 2 months ago)
- Topics: async, binary, fast, garrysmod, gmod, gmod-mysql, graceful, graceful-shutdown, mysql, rust, rust-lang, rustlang, simple, sql, transactions
- Language: Rust
- Homepage:
- Size: 69.3 KB
- Stars: 8
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Goobie MySQL
A simple and easy-to-use MySQL client for Garry's Mod.
## Version Information
The module exposes version constants that you can use to verify or log the library version:
- **`goobie_mysql.VERSION`**: Contains the complete version string.
- **`goobie_mysql.MAJOR_VERSION`**: Contains the major version number.## LuaLS
You can now use [LuaLS](https://github.com/LuaLS/lua-language-server) to get autocomplete and syntax highlighting for the library!
You can find the meta file in `luals/goobie_mysql.lua` (Don't ask me how to install because I don't know).
## Installation
1. Download the latest version from the [GitHub releases](https://github.com/Srlion/goobie-mysql/releases/latest).
2. Extract the module to your Garry's Mod `lua/bin` directory.**Note:** To avoid conflicts when multiple addons use different versions of the library, require the specific version you need:
```lua
require("goobie_mysql_1")---@type goobie_mysql
local goobie_mysql = goobie_mysql_1
```When installing the library, ensure you select the version you intend to use.
Previously, it was using SemVer, but I've changed it to use Float-Versioning.
## Establishing a Connection
Create a connection object using `goobie_mysql.NewConn`. You can specify connection options in two ways:
### Using a URI
#### URI Format
The URI format is `mysql://[user[:password]@][host][:port]/[database][?properties]`.
```lua
local conn = goobie_mysql.NewConn({
uri = "mysql://username:password@host:port/database"
})
```### Using Individual Credentials
```lua
local conn = goobie_mysql.NewConn({
host = "localhost",
username = "user",
password = "pass",
database = "mydb"
})
```Additional (optional) settings include:
- `charset` (e.g., `"utf8mb4"`)
- `collation` (e.g., `"utf8mb4_0900_ai_ci"`)
- `timezone` (e.g., `"UTC"`)
- `statement_cache_capacity` (e.g., `100`)
- `socket` (e.g., `"/path/to/socket"`)### Start the connection using either:
#### Asynchronous Connection
```lua
conn:Start(function(err)
if err then
print("Connection failed: " .. err.message)
else
print("Connected successfully")
end
end)
```#### Synchronous Connection
```lua
conn:StartSync()
```> **Note:** `StartSync` throws an error on failure, so consider using `pcall` to handle errors.
## Connection States
After starting a connection, you can check its state using the following methods:
- **Numeric State:** `conn:State()`
Returns a number corresponding to one of the state constants defined in `goobie_mysql.STATES`.- **State Name:** `conn:StateName()`
Returns a string representation of the current state (e.g., `"CONNECTED"`).Available states (available via `goobie_mysql.STATES`):
- `CONNECTED`
- `CONNECTING`
- `NOT_CONNECTED`
- `DISCONNECTED`Additional helper methods:
- `conn:IsConnected()`
- `conn:IsConnecting()`
- `conn:IsNotConnected()`
- `conn:IsDisconnected()`## Polling for Connection Events
For asynchronous operations that may not use callbacks directly, you can use the **`conn:Poll()`** method to process connection events.
## Disconnecting
When you need to close the connection, use one of the following methods:
#### Asynchronous Disconnection
```lua
conn:Disconnect(function(err)
if err then
print("Disconnection failed: " .. err.message)
else
print("Disconnected successfully")
end
end)
```#### Synchronous Disconnection
```lua
local err = conn:DisconnectSync()
if err then
print("Disconnection failed: " .. err.message)
else
print("Disconnected successfully")
end
```## Error Handling
Most methods return an `Error` object on failure. This object contains:
- **`message`**: A description of the error.
- **`code`**: A numeric error code.
- **`sqlstate`** (optional): The SQL state string provided by MySQL.Always check for errors after each operation to handle failures gracefully.
## Querying the Database
The module offers methods for running queries, with both asynchronous and synchronous versions.
### Run
For queries like INSERT, UPDATE, or DELETE that don’t return data.
#### Asynchronous
```lua
conn:Run("INSERT INTO mytable (column) VALUES (?)", {params = {"value"}}, function(err)
if err then
print("Query failed: " .. err.message)
else
print("Query executed successfully")
end
end)
```#### Synchronous
```lua
local err = conn:RunSync("INSERT INTO mytable (column) VALUES (?)", {params = {"value"}})
if err then
print("Query failed: " .. err.message)
else
print("Query executed successfully")
end
```### Execute
Like `Run`, but returns `rows_affected` and `last_insert_id`.
#### Asynchronous
```lua
conn:Execute("INSERT INTO mytable (column) VALUES (?)", {params = {"value"}}, function(err, result)
if err then
print("Query failed: " .. err.message)
else
print("Rows affected: " .. result.rows_affected)
print("Last insert ID: " .. result.last_insert_id)
end
end)
```#### Synchronous
```lua
local err, result = conn:ExecuteSync("INSERT INTO mytable (column) VALUES (?)", {params = {"value"}})
if err then
print("Query failed: " .. err.message)
else
print("Rows affected: " .. result.rows_affected)
print("Last insert ID: " .. result.last_insert_id)
end
```### Fetch
Retrieves multiple rows from a SELECT query.
#### Asynchronous
```lua
conn:Fetch("SELECT * FROM mytable WHERE column = ?", {params = {"value"}}, function(err, rows)
if err then
print("Query failed: " .. err.message)
else
for _, row in ipairs(rows) do
print(row.column)
end
end
end)
```#### Synchronous
```lua
local err, rows = conn:FetchSync("SELECT * FROM mytable WHERE column = ?", {params = {"value"}})
if err then
print("Query failed: " .. err.message)
else
for _, row in ipairs(rows) do
print(row.column)
end
end
```### FetchOne
Retrieves a single row from a SELECT query.
#### Asynchronous
```lua
conn:FetchOne("SELECT * FROM mytable WHERE id = ?", {params = {1}}, function(err, row)
if err then
print("Query failed: " .. err.message)
elseif row then
print(row.column)
else
print("No row found")
end
end)
```#### Synchronous
```lua
local err, row = conn:FetchOneSync("SELECT * FROM mytable WHERE id = ?", {params = {1}})
if err then
print("Query failed: " .. err.message)
elseif row then
print(row.column)
else
print("No row found")
end
```### Query Parameters
To prevent SQL injection, always use the `params` field:
```lua
{params = {"value1", "value2"}}
```For raw queries (such as multi-statement queries), set `raw = true`. Use this option with caution and avoid with untrusted input.
## Transactions
Group queries into a transaction that can be committed or rolled back.
### Asynchronous Transaction
```lua
conn:Begin(function(err, txn)
if err then
print("Failed to start transaction: " .. err.message)
return
end
local err, rows = txn:Fetch("SELECT * FROM mytable")
if err then
print("Query failed: " .. err.message)
txn:Rollback()
return
end
local err = txn:Commit()
if err then
print("Commit failed: " .. err.message)
end
end)
```### Synchronous Transaction
```lua
conn:BeginSync(function(err, txn)
if err then
print("Failed to start transaction: " .. err.message)
return
end
local err = txn:Run("INSERT INTO mytable (column) VALUES ('value')")
if err then
txn:Rollback()
return
end
txn:Commit()
end)
```Inside a transaction:
- All query methods (`Run`, `Execute`, `Fetch`, `FetchOne`) are synchronous and do not take a callback.
- Check transaction status with `txn:IsOpen()`.
- Finalize the transaction using `txn:Commit()` or `txn:Rollback()`.## Ping
Test the connection with a ping (note: it’s not a reliable method to check if the connection is alive).
### Asynchronous
```lua
conn:Ping(function(err, latency)
if err then
print("Ping failed: " .. err.message)
else
print("Latency: " .. latency .. "ms")
end
end)
```### Synchronous
```lua
local err, latency = conn:PingSync()
if err then
print("Ping failed: " .. err.message)
else
print("Latency: " .. latency .. "ms")
end
```## Examples
### Simple Query
```lua
local goobie_mysql = require("goobie_mysql")local conn = goobie_mysql.NewConn({
host = "localhost",
username = "user",
password = "pass",
database = "mydb"
})conn:StartSync()
local err, rows = conn:FetchSync("SELECT * FROM mytable")
if err then
print("Query failed: " .. err.message)
else
for _, row in ipairs(rows) do
print(row.column)
end
end
```### Transaction Example
```lua
local goobie_mysql = require("goobie_mysql")local conn = goobie_mysql.NewConn({
host = "localhost",
username = "user",
password = "pass",
database = "mydb"
})conn:StartSync()
conn:BeginSync(function(err, txn)
if err then
print("Failed to start transaction: " .. err.message)
return
end
local err = txn:Run("INSERT INTO mytable (column) VALUES ('value1')")
if err then
print("Insert failed: " .. err.message)
txn:Rollback()
return
end
local err = txn:Run("INSERT INTO mytable (column) VALUES ('value2')")
if err then
print("Insert failed: " .. err.message)
txn:Rollback()
return
end
local err = txn:Commit()
if err then
print("Commit failed: " .. err.message)
end
end)
```