{"id":26038296,"url":"https://github.com/srlion/goobie-mysql","last_synced_at":"2025-03-07T09:13:48.275Z","repository":{"id":259003898,"uuid":"868399238","full_name":"Srlion/goobie-mysql","owner":"Srlion","description":"Easily connect to MySQL in Garry's Mod using Rust binary!","archived":false,"fork":false,"pushed_at":"2025-03-06T09:59:02.000Z","size":71,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-06T10:23:10.349Z","etag":null,"topics":["async","binary","fast","garrysmod","gmod","gmod-mysql","graceful","graceful-shutdown","mysql","rust","rust-lang","rustlang","simple","sql","transactions"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Srlion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-06T09:35:08.000Z","updated_at":"2025-03-06T09:58:55.000Z","dependencies_parsed_at":"2025-01-11T01:33:41.156Z","dependency_job_id":"306dafb2-2b11-4268-b76e-b03e5d52e572","html_url":"https://github.com/Srlion/goobie-mysql","commit_stats":null,"previous_names":["srlion/goobie-mysql"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Srlion%2Fgoobie-mysql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Srlion%2Fgoobie-mysql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Srlion%2Fgoobie-mysql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Srlion%2Fgoobie-mysql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Srlion","download_url":"https://codeload.github.com/Srlion/goobie-mysql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242361836,"owners_count":20115411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","binary","fast","garrysmod","gmod","gmod-mysql","graceful","graceful-shutdown","mysql","rust","rust-lang","rustlang","simple","sql","transactions"],"created_at":"2025-03-07T09:13:47.651Z","updated_at":"2025-03-07T09:13:48.269Z","avatar_url":"https://github.com/Srlion.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Goobie MySQL\n\nA simple and easy-to-use MySQL client for Garry's Mod.\n\n## Version Information\n\nThe module exposes version constants that you can use to verify or log the library version:\n\n- **`goobie_mysql.VERSION`**: Contains the complete version string.\n- **`goobie_mysql.MAJOR_VERSION`**: Contains the major version number.\n\n## LuaLS\n\nYou can now use [LuaLS](https://github.com/LuaLS/lua-language-server) to get autocomplete and syntax highlighting for the library!\n\nYou can find the meta file in `luals/goobie_mysql.lua` (Don't ask me how to install because I don't know).\n\n## Installation\n\n1. Download the latest version from the [GitHub releases](https://github.com/Srlion/goobie-mysql/releases/latest).\n2. Extract the module to your Garry's Mod `lua/bin` directory.\n\n**Note:** To avoid conflicts when multiple addons use different versions of the library, require the specific version you need:\n\n```lua\nrequire(\"goobie_mysql_1\")\n\n---@type goobie_mysql\nlocal goobie_mysql = goobie_mysql_1\n```\n\nWhen installing the library, ensure you select the version you intend to use.\n\nPreviously, it was using SemVer, but I've changed it to use Float-Versioning.\n\n## Establishing a Connection\n\nCreate a connection object using `goobie_mysql.NewConn`. You can specify connection options in two ways:\n\n### Using a URI\n\n#### URI Format\n\nThe URI format is `mysql://[user[:password]@][host][:port]/[database][?properties]`.\n\n```lua\nlocal conn = goobie_mysql.NewConn({\n    uri = \"mysql://username:password@host:port/database\"\n})\n```\n\n### Using Individual Credentials\n\n```lua\nlocal conn = goobie_mysql.NewConn({\n    host = \"localhost\",\n    username = \"user\",\n    password = \"pass\",\n    database = \"mydb\"\n})\n```\n\nAdditional (optional) settings include:\n\n- `charset` (e.g., `\"utf8mb4\"`)\n- `collation` (e.g., `\"utf8mb4_0900_ai_ci\"`)\n- `timezone` (e.g., `\"UTC\"`)\n- `statement_cache_capacity` (e.g., `100`)\n- `socket` (e.g., `\"/path/to/socket\"`)\n\n### Start the connection using either:\n\n#### Asynchronous Connection\n\n```lua\nconn:Start(function(err)\n    if err then\n        print(\"Connection failed: \" .. err.message)\n    else\n        print(\"Connected successfully\")\n    end\nend)\n```\n\n#### Synchronous Connection\n\n```lua\nconn:StartSync()\n```\n\n\u003e **Note:** `StartSync` throws an error on failure, so consider using `pcall` to handle errors.\n\n## Connection States\n\nAfter starting a connection, you can check its state using the following methods:\n\n- **Numeric State:** `conn:State()`\n  Returns a number corresponding to one of the state constants defined in `goobie_mysql.STATES`.\n\n- **State Name:** `conn:StateName()`\n  Returns a string representation of the current state (e.g., `\"CONNECTED\"`).\n\nAvailable states (available via `goobie_mysql.STATES`):\n\n- `CONNECTED`\n- `CONNECTING`\n- `NOT_CONNECTED`\n- `DISCONNECTED`\n\nAdditional helper methods:\n\n- `conn:IsConnected()`\n- `conn:IsConnecting()`\n- `conn:IsNotConnected()`\n- `conn:IsDisconnected()`\n\n## Polling for Connection Events\n\nFor asynchronous operations that may not use callbacks directly, you can use the **`conn:Poll()`** method to process connection events.\n\n## Disconnecting\n\nWhen you need to close the connection, use one of the following methods:\n\n#### Asynchronous Disconnection\n\n```lua\nconn:Disconnect(function(err)\n    if err then\n        print(\"Disconnection failed: \" .. err.message)\n    else\n        print(\"Disconnected successfully\")\n    end\nend)\n```\n\n#### Synchronous Disconnection\n\n```lua\nlocal err = conn:DisconnectSync()\nif err then\n    print(\"Disconnection failed: \" .. err.message)\nelse\n    print(\"Disconnected successfully\")\nend\n```\n\n## Error Handling\n\nMost methods return an `Error` object on failure. This object contains:\n\n- **`message`**: A description of the error.\n- **`code`**: A numeric error code.\n- **`sqlstate`** (optional): The SQL state string provided by MySQL.\n\nAlways check for errors after each operation to handle failures gracefully.\n\n## Querying the Database\n\nThe module offers methods for running queries, with both asynchronous and synchronous versions.\n\n### Run\n\nFor queries like INSERT, UPDATE, or DELETE that don’t return data.\n\n#### Asynchronous\n\n```lua\nconn:Run(\"INSERT INTO mytable (column) VALUES (?)\", {params = {\"value\"}}, function(err)\n    if err then\n        print(\"Query failed: \" .. err.message)\n    else\n        print(\"Query executed successfully\")\n    end\nend)\n```\n\n#### Synchronous\n\n```lua\nlocal err = conn:RunSync(\"INSERT INTO mytable (column) VALUES (?)\", {params = {\"value\"}})\nif err then\n    print(\"Query failed: \" .. err.message)\nelse\n    print(\"Query executed successfully\")\nend\n```\n\n### Execute\n\nLike `Run`, but returns `rows_affected` and `last_insert_id`.\n\n#### Asynchronous\n\n```lua\nconn:Execute(\"INSERT INTO mytable (column) VALUES (?)\", {params = {\"value\"}}, function(err, result)\n    if err then\n        print(\"Query failed: \" .. err.message)\n    else\n        print(\"Rows affected: \" .. result.rows_affected)\n        print(\"Last insert ID: \" .. result.last_insert_id)\n    end\nend)\n```\n\n#### Synchronous\n\n```lua\nlocal err, result = conn:ExecuteSync(\"INSERT INTO mytable (column) VALUES (?)\", {params = {\"value\"}})\nif err then\n    print(\"Query failed: \" .. err.message)\nelse\n    print(\"Rows affected: \" .. result.rows_affected)\n    print(\"Last insert ID: \" .. result.last_insert_id)\nend\n```\n\n### Fetch\n\nRetrieves multiple rows from a SELECT query.\n\n#### Asynchronous\n\n```lua\nconn:Fetch(\"SELECT * FROM mytable WHERE column = ?\", {params = {\"value\"}}, function(err, rows)\n    if err then\n        print(\"Query failed: \" .. err.message)\n    else\n        for _, row in ipairs(rows) do\n            print(row.column)\n        end\n    end\nend)\n```\n\n#### Synchronous\n\n```lua\nlocal err, rows = conn:FetchSync(\"SELECT * FROM mytable WHERE column = ?\", {params = {\"value\"}})\nif err then\n    print(\"Query failed: \" .. err.message)\nelse\n    for _, row in ipairs(rows) do\n        print(row.column)\n    end\nend\n```\n\n### FetchOne\n\nRetrieves a single row from a SELECT query.\n\n#### Asynchronous\n\n```lua\nconn:FetchOne(\"SELECT * FROM mytable WHERE id = ?\", {params = {1}}, function(err, row)\n    if err then\n        print(\"Query failed: \" .. err.message)\n    elseif row then\n        print(row.column)\n    else\n        print(\"No row found\")\n    end\nend)\n```\n\n#### Synchronous\n\n```lua\nlocal err, row = conn:FetchOneSync(\"SELECT * FROM mytable WHERE id = ?\", {params = {1}})\nif err then\n    print(\"Query failed: \" .. err.message)\nelseif row then\n    print(row.column)\nelse\n    print(\"No row found\")\nend\n```\n\n### Query Parameters\n\nTo prevent SQL injection, always use the `params` field:\n\n```lua\n{params = {\"value1\", \"value2\"}}\n```\n\nFor raw queries (such as multi-statement queries), set `raw = true`. Use this option with caution and avoid with untrusted input.\n\n## Transactions\n\nGroup queries into a transaction that can be committed or rolled back.\n\n### Asynchronous Transaction\n\n```lua\nconn:Begin(function(err, txn)\n    if err then\n        print(\"Failed to start transaction: \" .. err.message)\n        return\n    end\n    local err, rows = txn:Fetch(\"SELECT * FROM mytable\")\n    if err then\n        print(\"Query failed: \" .. err.message)\n        txn:Rollback()\n        return\n    end\n    local err = txn:Commit()\n    if err then\n        print(\"Commit failed: \" .. err.message)\n    end\nend)\n```\n\n### Synchronous Transaction\n\n```lua\nconn:BeginSync(function(err, txn)\n    if err then\n        print(\"Failed to start transaction: \" .. err.message)\n        return\n    end\n    local err = txn:Run(\"INSERT INTO mytable (column) VALUES ('value')\")\n    if err then\n        txn:Rollback()\n        return\n    end\n    txn:Commit()\nend)\n```\n\nInside a transaction:\n\n- All query methods (`Run`, `Execute`, `Fetch`, `FetchOne`) are synchronous and do not take a callback.\n- Check transaction status with `txn:IsOpen()`.\n- Finalize the transaction using `txn:Commit()` or `txn:Rollback()`.\n\n## Ping\n\nTest the connection with a ping (note: it’s not a reliable method to check if the connection is alive).\n\n### Asynchronous\n\n```lua\nconn:Ping(function(err, latency)\n    if err then\n        print(\"Ping failed: \" .. err.message)\n    else\n        print(\"Latency: \" .. latency .. \"ms\")\n    end\nend)\n```\n\n### Synchronous\n\n```lua\nlocal err, latency = conn:PingSync()\nif err then\n    print(\"Ping failed: \" .. err.message)\nelse\n    print(\"Latency: \" .. latency .. \"ms\")\nend\n```\n\n## Examples\n\n### Simple Query\n\n```lua\nlocal goobie_mysql = require(\"goobie_mysql\")\n\nlocal conn = goobie_mysql.NewConn({\n    host = \"localhost\",\n    username = \"user\",\n    password = \"pass\",\n    database = \"mydb\"\n})\n\nconn:StartSync()\n\nlocal err, rows = conn:FetchSync(\"SELECT * FROM mytable\")\nif err then\n    print(\"Query failed: \" .. err.message)\nelse\n    for _, row in ipairs(rows) do\n        print(row.column)\n    end\nend\n```\n\n### Transaction Example\n\n```lua\nlocal goobie_mysql = require(\"goobie_mysql\")\n\nlocal conn = goobie_mysql.NewConn({\n    host = \"localhost\",\n    username = \"user\",\n    password = \"pass\",\n    database = \"mydb\"\n})\n\nconn:StartSync()\n\nconn:BeginSync(function(err, txn)\n    if err then\n        print(\"Failed to start transaction: \" .. err.message)\n        return\n    end\n    local err = txn:Run(\"INSERT INTO mytable (column) VALUES ('value1')\")\n    if err then\n        print(\"Insert failed: \" .. err.message)\n        txn:Rollback()\n        return\n    end\n    local err = txn:Run(\"INSERT INTO mytable (column) VALUES ('value2')\")\n    if err then\n        print(\"Insert failed: \" .. err.message)\n        txn:Rollback()\n        return\n    end\n    local err = txn:Commit()\n    if err then\n        print(\"Commit failed: \" .. err.message)\n    end\nend)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrlion%2Fgoobie-mysql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsrlion%2Fgoobie-mysql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrlion%2Fgoobie-mysql/lists"}