BLD - add standalone phone development workflow

This commit is contained in:
smx.pusha
2026-08-06 08:23:14 +02:00
parent 5471040dd8
commit 0a880bc4d4
72 changed files with 6856 additions and 1 deletions
+42
View File
@@ -0,0 +1,42 @@
---
name: oxmysql
description: "OxMySQL for FiveM - SQL integrations with MySQL/MariaDB. Use when writing or editing server-side database code: queries, inserts, updates, transactions, or any resource that uses oxmysql (query, insert, prepare, update, single, scalar, rawExecute, transaction)."
author: germanfndez
version: "1.0.0"
mcp-server: projecthub
---
# OxMySQL
SQL integration for FiveM using OxMySQL (replacement for mysql-async / ghmattimysql). Server-side only. Use MariaDB over MySQL 8 for compatibility.
## When to use
- User asks for database queries, inserts, updates, or SQL in a FiveM resource.
- Editing or writing code that uses `MySQL.*` or `exports.oxmysql`.
- Designing tables, upserts, or transactions.
## Setup
- Lua: `server_script '@oxmysql/lib/MySQL.lua'` in fxmanifest (above other scripts).
## Rules
Read the rule that matches what you're doing:
- **rules/placeholders.md** — Safe parameters (`?` placeholders), avoid SQL injection.
- **rules/query.md** — `MySQL.query` / `MySQL.query.await`: SELECT returns rows; other statements return insertId/affectedRows.
- **rules/insert.md** — `MySQL.insert`: insert row, returns insert id.
- **rules/prepare.md** — `MySQL.prepare`: prepared statements, only `?` placeholders; faster for repeated queries.
- **rules/update.md** — `MySQL.update`: update rows, returns affected count.
- **rules/single.md** — `MySQL.single`: one row or nil.
- **rules/scalar.md** — `MySQL.scalar`: single value (one row, one column).
- **rules/rawExecute.md** — `MySQL.rawExecute`: raw execution, no automatic result shape.
- **rules/transaction.md** — `MySQL.transaction`: run multiple queries in a transaction.
## References (look up if not covered in the rules above)
If something isn't covered in the rules above, check the official docs:
- **OxMySQL (index):** https://coxdocs.dev/oxmysql
- **Placeholders:** https://coxdocs.dev/oxmysql/placeholders
- **Functions (query, insert, prepare, update, single, scalar, rawExecute, transaction):** https://coxdocs.dev/oxmysql (Functions section)
+26
View File
@@ -0,0 +1,26 @@
# insert
Inserts a row and returns the insert id (or nil/falsy on failure).
**Lua (Promise)**
```lua
local id = MySQL.insert.await('INSERT INTO `users` (identifier, firstname, lastname) VALUES (?, ?, ?)', { identifier, firstName, lastName })
print(id)
```
**Lua (Callback)**
```lua
MySQL.insert('INSERT INTO `users` (identifier, firstname, lastname) VALUES (?, ?, ?)', { identifier, firstName, lastName }, function(id)
print(id)
end)
```
**JavaScript**
```js
const insertId = await MySQL.insert('INSERT INTO `users` (identifier, firstname, lastname) VALUES (?, ?, ?)', [identifier, firstName, lastName]);
```
Reference: [insert coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/insert).
+11
View File
@@ -0,0 +1,11 @@
# Placeholders
Use `?` for values; parameters as array or object. Prevents SQL injection.
```lua
MySQL.scalar('SELECT `username` FROM `users` WHERE `identifier` = ? AND `group` = ?', { identifier, group })
```
Named placeholders (`@name`) are deprecated; use positional `?` and pass array. For prepared statements use **rules/prepare.md** (only `?` and `??` for column names).
Reference: [Placeholders coxdocs.dev](https://coxdocs.dev/oxmysql/placeholders).
+29
View File
@@ -0,0 +1,29 @@
# prepare
Prepared statements: faster for repeated queries. **Only `?` (value) and `??` (column name) placeholders** — named placeholders throw.
- Date does not return the datestring commonly used in FiveM.
- TINYINT(1) and BIT do not return boolean.
- SELECT result shape: column, row, or array of rows depending on columns/rows selected (unlike rawExecute).
**Lua (Promise)**
```lua
local response = MySQL.prepare.await('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', { identifier })
```
**Lua (Callback)**
```lua
MySQL.prepare('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', { identifier }, function(response)
-- use response
end)
```
**Upsert (insert or update on duplicate)**
```lua
MySQL.prepare('INSERT INTO ox_inventory (owner, name, data) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE data = VALUES(data)', { owner, dbId, inventory })
```
Reference: [prepare coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/prepare).
+37
View File
@@ -0,0 +1,37 @@
# query
SELECT returns all matching rows (array of rows). Other statements return insertId, affectedRows, etc.
**Lua (Promise)**
```lua
local response = MySQL.query.await('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', { identifier })
if response then
for i = 1, #response do
local row = response[i]
print(row.firstname, row.lastname)
end
end
```
**Lua (Callback)**
```lua
MySQL.query('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', { identifier }, function(response)
if response then
for i = 1, #response do
local row = response[i]
print(row.firstname, row.lastname)
end
end
end)
```
**JavaScript**
```js
const rows = await MySQL.query('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', [identifier]);
// rows is array of objects
```
Reference: [query coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/query).
+19
View File
@@ -0,0 +1,19 @@
# rawExecute
Executes raw SQL. Does not normalize result shape like query/prepare (SELECT returns raw result). Use when you need full control or non-standard result handling.
**Lua (Promise)**
```lua
local result = MySQL.rawExecute.await('DELETE FROM `sessions` WHERE `expires` < NOW()')
```
**Lua (Callback)**
```lua
MySQL.rawExecute('DELETE FROM `sessions` WHERE `expires` < NOW()', {}, function(result)
-- raw result
end)
```
Prefer **query**, **insert**, **update**, **single**, **scalar**, or **prepare** when they match the use case; use rawExecute only when necessary. Reference: [rawExecute coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/rawExecute).
+27
View File
@@ -0,0 +1,27 @@
# scalar
Returns a single value (one row, one column). Use for COUNT, one field, etc.
**Lua (Promise)**
```lua
local count = MySQL.scalar.await('SELECT COUNT(*) FROM `users` WHERE `group` = ?', { group })
local name = MySQL.scalar.await('SELECT `username` FROM `users` WHERE `identifier` = ?', { identifier })
```
**Lua (Callback)**
```lua
MySQL.scalar('SELECT `username` FROM `users` WHERE `identifier` = ?', { identifier }, function(name)
if name then print(name) end
end)
```
**JavaScript**
```js
const count = await MySQL.scalar('SELECT COUNT(*) FROM `users` WHERE `group` = ?', [group]);
const name = await MySQL.scalar('SELECT `username` FROM `users` WHERE `identifier` = ?', [identifier]);
```
Reference: [scalar coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/scalar).
+29
View File
@@ -0,0 +1,29 @@
# single
Returns a single row (first match) or nil/null if none.
**Lua (Promise)**
```lua
local user = MySQL.single.await('SELECT * FROM `users` WHERE `identifier` = ?', { identifier })
if user then
print(user.firstname, user.lastname)
end
```
**Lua (Callback)**
```lua
MySQL.single('SELECT * FROM `users` WHERE `identifier` = ?', { identifier }, function(user)
if user then print(user.firstname) end
end)
```
**JavaScript**
```js
const user = await MySQL.single('SELECT * FROM `users` WHERE `identifier` = ?', [identifier]);
// user is one object or null
```
Reference: [single coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/single).
+35
View File
@@ -0,0 +1,35 @@
# transaction
Run multiple queries in a transaction. If any fails, the transaction is rolled back.
**Lua (Promise)**
```lua
MySQL.transaction.await({
{ query = 'UPDATE `accounts` SET `balance` = `balance` - ? WHERE `id` = ?', values = { amount, fromId } },
{ query = 'UPDATE `accounts` SET `balance` = `balance` + ? WHERE `id` = ?', values = { amount, toId } },
})
```
**Lua (Callback)**
```lua
MySQL.transaction({
{ query = 'UPDATE `accounts` SET `balance` = `balance` - ? WHERE `id` = ?', values = { amount, fromId } },
{ query = 'UPDATE `accounts` SET `balance` = `balance` + ? WHERE `id` = ?', values = { amount, toId } },
}, function(success)
if not success then -- rollback happened
end
end)
```
**JavaScript**
```js
await MySQL.transaction([
{ query: 'UPDATE `accounts` SET `balance` = `balance` - ? WHERE `id` = ?', values: [amount, fromId] },
{ query: 'UPDATE `accounts` SET `balance` = `balance` + ? WHERE `id` = ?', values: [amount, toId] },
]);
```
Reference: [transaction coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/transaction).
+25
View File
@@ -0,0 +1,25 @@
# update
Updates rows; returns affected row count (or result object with affectedRows).
**Lua (Promise)**
```lua
local affected = MySQL.update.await('UPDATE `users` SET `lastname` = ? WHERE `identifier` = ?', { newLastName, identifier })
```
**Lua (Callback)**
```lua
MySQL.update('UPDATE `users` SET `lastname` = ? WHERE `identifier` = ?', { newLastName, identifier }, function(affected)
-- use affected
end)
```
**JavaScript**
```js
const result = await MySQL.update('UPDATE `users` SET `lastname` = ? WHERE `identifier` = ?', [newLastName, identifier]);
```
Always use `?` placeholders for values. Reference: [update coxdocs.dev](https://coxdocs.dev/oxmysql/Functions/update).