├── .gitignore ├── src ├── ui │ ├── tailwind.css │ ├── fonts │ │ ├── fira-sans-v9-latin-700.woff │ │ ├── fira-sans-v9-latin-700.woff2 │ │ ├── fira-sans-v9-latin-italic.woff │ │ ├── fira-sans-v9-latin-italic.woff2 │ │ ├── fira-sans-v9-latin-regular.woff │ │ └── fira-sans-v9-latin-regular.woff2 │ └── Nui.vue ├── docs │ ├── .gitignore │ ├── content │ │ ├── configOptions │ │ │ ├── password.md │ │ │ ├── port.md │ │ │ ├── localAddress.md │ │ │ ├── user.md │ │ │ ├── database.md │ │ │ ├── localInfile.md │ │ │ ├── connectionLimit.md │ │ │ ├── stringifyObjects.md │ │ │ ├── socketPath.md │ │ │ ├── host.md │ │ │ ├── insecureAuth.md │ │ │ ├── connectTimeout.md │ │ │ ├── ssl.md │ │ │ ├── debug.md │ │ │ ├── supportBigNumbers.md │ │ │ ├── multipleStatements.md │ │ │ ├── trace.md │ │ │ ├── flags.md │ │ │ ├── queueLimit.md │ │ │ ├── timezone.md │ │ │ ├── charset.md │ │ │ ├── waitForConnections.md │ │ │ ├── acquireTimeout.md │ │ │ └── bigNumberStrings.md │ │ ├── pages │ │ │ ├── setup.md │ │ │ ├── setupDatabaseOptions.md │ │ │ ├── configurationAdditional.md │ │ │ ├── configurationOptions.md │ │ │ ├── gui&devTogglePrint.md │ │ │ ├── configuration.md │ │ │ ├── setupResource.md │ │ │ ├── gui&dev.md │ │ │ ├── transactions.md │ │ │ └── queries.md │ │ ├── serverVars │ │ │ ├── mysqlSlowQueryWarning.md │ │ │ ├── mysqlLogFileFormat.md │ │ │ ├── mysqlLogLevel.md │ │ │ └── mysqlDebug.md │ │ └── setup │ │ │ └── setupResource.md │ ├── src │ │ ├── assets │ │ │ └── img │ │ │ │ └── gui.webp │ │ ├── styles │ │ │ └── index.scss │ │ ├── pages │ │ │ ├── Gui.vue │ │ │ ├── Queries.vue │ │ │ ├── Config.vue │ │ │ └── Index.vue │ │ ├── main.js │ │ ├── layouts │ │ │ └── Default.vue │ │ └── components │ │ │ ├── Benchmark.vue │ │ │ └── ConfigFXServer.vue │ ├── package.json │ ├── gridsome.server.js │ └── gridsome.config.js ├── entry │ ├── nui.js │ └── server.ts ├── tsconfig.json ├── vue.config.js ├── tailwind.config.js ├── .eslintrc.js ├── template │ └── index.html ├── postcss.config.js ├── webpack.config.js └── package.json ├── ui ├── fonts │ ├── MaterialIcons-Regular.eot │ ├── MaterialIcons-Regular.ttf │ ├── MaterialIcons-Regular.woff │ ├── MaterialIcons-Regular.woff2 │ ├── fira-sans-v9-latin-700.woff │ ├── fira-sans-v9-latin-700.woff2 │ ├── fira-sans-v9-latin-italic.woff │ ├── fira-sans-v9-latin-italic.woff2 │ ├── fira-sans-v9-latin-regular.woff │ └── fira-sans-v9-latin-regular.woff2 ├── index.html └── css │ └── app.css ├── .gitmodules ├── .editorconfig ├── .circleci └── config.yml ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── fxmanifest.lua ├── LICENSE ├── README.md ├── example.lua ├── mysql-async-client.lua └── lib └── MySQL.lua /.gitignore: -------------------------------------------------------------------------------- 1 | src/node_modules 2 | src/package-lock.json 3 | dist 4 | 5 | .idea 6 | -------------------------------------------------------------------------------- /src/ui/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/docs/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .cache 3 | .DS_Store 4 | src/.temp 5 | node_modules 6 | dist 7 | .env 8 | .env.* 9 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/password.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 6 3 | name: 'password | pwd' 4 | --- 5 | The password of that MySQL user. -------------------------------------------------------------------------------- /src/docs/src/assets/img/gui.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/docs/src/assets/img/gui.webp -------------------------------------------------------------------------------- /src/docs/content/configOptions/port.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 2 3 | name: 'port' 4 | --- 5 | The port number to connect to. (Default: `3306`) -------------------------------------------------------------------------------- /ui/fonts/MaterialIcons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/MaterialIcons-Regular.eot -------------------------------------------------------------------------------- /ui/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /ui/fonts/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /ui/fonts/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-700.woff -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-700.woff2 -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-700.woff -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-italic.woff -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-italic.woff2 -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-regular.woff -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-700.woff2 -------------------------------------------------------------------------------- /ui/fonts/fira-sans-v9-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/ui/fonts/fira-sans-v9-latin-regular.woff2 -------------------------------------------------------------------------------- /src/docs/content/pages/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 11 3 | --- 4 | ## Setup 5 | 6 | To Install mysql-async your first need to have installed a MySQL Database. -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-italic.woff -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-italic.woff2 -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-regular.woff -------------------------------------------------------------------------------- /src/ui/fonts/fira-sans-v9-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brouznouf/fivem-mysql-async/HEAD/src/ui/fonts/fira-sans-v9-latin-regular.woff2 -------------------------------------------------------------------------------- /src/docs/content/configOptions/localAddress.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 3 3 | name: 'localAddress' 4 | --- 5 | The source IP address to use for TCP connection. (Optional) -------------------------------------------------------------------------------- /src/docs/content/configOptions/user.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 5 3 | name: 'user | user id | userid | user name | username | uid' 4 | --- 5 | The MySQL user to authenticate as. -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/vendor/ghmattimysql"] 2 | path = src/vendor/ghmattimysql 3 | url = https://github.com/GHMatti/ghmattimysql.git 4 | branch = master 5 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/database.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 7 3 | name: 'database | initial catalog' 4 | --- 5 | Name of the database to use for this connection (Optional). -------------------------------------------------------------------------------- /src/docs/content/configOptions/localInfile.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 17 3 | name: 'localInfile' 4 | --- 5 | Allow `LOAD DATA INFILE` to use the LOCAL modifier. (Default: `true`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/connectionLimit.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 23 3 | name: 'connectionLimit' 4 | --- 5 | The maximum number of connections to create at once. (Default: `10`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/stringifyObjects.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 11 3 | name: 'stringifyObjects' 4 | --- 5 | Stringify objects instead of converting to values. (Default: `false`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/socketPath.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 4 3 | name: 'socketPath' 4 | --- 5 | The path to a unix domain socket to connect to. When used `host` and `port` are ignored. -------------------------------------------------------------------------------- /src/docs/content/configOptions/host.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 1 3 | name: 'host | server | data source | datasource | addr | address' 4 | --- 5 | The hostname of the database you are connecting to. (Default: `localhost`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/insecureAuth.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 12 3 | name: 'insecureAuth' 4 | --- 5 | Allow connecting to MySQL instances that ask for the old (insecure) authentication method. (Default: `false`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/connectTimeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 10 3 | name: 'connectTimeout' 4 | --- 5 | The milliseconds before a timeout occurs during the initial connection to the MySQL server. (Default: `10000`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/ssl.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 20 3 | name: 'ssl' 4 | --- 5 | Object with ssl parameters or a string containing name of ssl profile. See [SSL options](https://github.com/mysqljs/mysql#ssl-options). -------------------------------------------------------------------------------- /src/docs/content/configOptions/debug.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 15 3 | name: 'debug' 4 | --- 5 | Prints protocol details to stdout. Can be `true`/`false` or an array of packet type names that should be 6 | printed. (Default: `false`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/supportBigNumbers.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 13 3 | name: 'supportBigNumbers' 4 | --- 5 | When dealing with big numbers (BIGINT and DECIMAL columns) in the database, you should enable this option (Default: `false`). -------------------------------------------------------------------------------- /src/docs/content/configOptions/multipleStatements.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 18 3 | name: 'multipleStatements' 4 | --- 5 | Allow multiple mysql statements per query. Be careful with this, it could increase the scope of SQL injection attacks. (Default: `false`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/trace.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 16 3 | name: 'trace' 4 | --- 5 | Generates stack traces on `Error` to include call site of library entrance ("long stack traces"). 6 | Slight performance penalty for most calls. (Default: `true`) -------------------------------------------------------------------------------- /src/docs/content/pages/setupDatabaseOptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 14 3 | --- 4 | 5 | #### Database Options 6 | 7 | Included in the table are the benchmark results of 1,000,000 inserts, with 20 done per server tick, that should mean it is about 100 inserts per second. 8 | -------------------------------------------------------------------------------- /src/docs/content/pages/configurationAdditional.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 25 3 | --- 4 | #### Additional Configuration Options 5 | 6 | These additional configuration are to be set in the server configuration file, in a similar way to 7 | setting the `mysql_connection_string`. 8 | -------------------------------------------------------------------------------- /src/entry/nui.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from '../ui/Nui.vue'; 3 | import 'material-design-icons-iconfont/dist/material-design-icons.css'; 4 | 5 | Vue.config.productionTip = false; 6 | 7 | new Vue({ 8 | render: (h) => h(App), 9 | }).$mount('#app'); 10 | -------------------------------------------------------------------------------- /src/docs/content/serverVars/mysqlSlowQueryWarning.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 3 3 | name: 'mysql_slow_query_warning' 4 | --- 5 | Sets a limit in millisecondss, queries slower than this limit will be displayed with a warning at the specified location of 6 | `mysql_debug_output`, see above (Default: `100`) -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [**.js] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | max_line_length = null 11 | 12 | [**.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/flags.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 19 3 | name: 'flags' 4 | --- 5 | List of connection flags to use other than the default ones. It is also possible to blacklist default ones. 6 | For more information, check [Connection Flags](https://github.com/mysqljs/mysql#connection-flags). -------------------------------------------------------------------------------- /src/docs/content/configOptions/queueLimit.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 24 3 | name: 'queueLimit' 4 | --- 5 | The maximum number of connection requests the pool will queue before returning an error from `getConnection`. 6 | If set to `0`, there is no limit to the number of queued connection requests. (Default: `0`) -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "commonjs", 5 | "types": ["@citizenfx/client", "@citizenfx/server", "@types/node", "@types/mysql"], 6 | }, 7 | "include": [ 8 | "**/*" 9 | ], 10 | "exclude": [ 11 | "node_modules" 12 | ] 13 | } -------------------------------------------------------------------------------- /src/docs/content/configOptions/timezone.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 9 3 | name: 'timezone' 4 | --- 5 | The timezone configured on the MySQL server. This is used to type cast server date/time values to JavaScript Date object 6 | and vice versa. This can be `'local'`, `'Z'`, or an offset in the form `+HH:MM` or 7 | `-HH:MM.` (Default: `'local'`) -------------------------------------------------------------------------------- /src/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | publicPath: './', 3 | outputDir: '../ui', 4 | filenameHashing: false, 5 | productionSourceMap: false, 6 | chainWebpack: (config) => { 7 | config.optimization.delete('splitChunks'); 8 | config.externals({ 9 | moment: 'moment', 10 | }); 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/charset.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 8 3 | name: 'charset' 4 | --- 5 | The charset for the connection. This is called "collation" in the SQL-level of MySQL (like `utf8_general_ci`). 6 | If a SQL-level charset is specified (like `utf8mb4`) then the default collation for that charset is used. 7 | (Default: `'UTF8_GENERAL_CI'`) -------------------------------------------------------------------------------- /src/docs/content/pages/configurationOptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 23 3 | --- 4 | 5 | #### Configuration Options 6 | 7 | This is taken directly from the [mysql.js Readme file](https://github.com/mysqljs/mysql#connection-options), but trimmed to only applicable connection and pooling options, or changed a bit to accomodate legacy settings. 8 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build-and-lint: 4 | docker: 5 | - image: circleci/node:latest 6 | steps: 7 | - checkout 8 | - run: cd src && npm install 9 | - run: cd src && npm run lint 10 | - run: cd src && npm run build 11 | workflows: 12 | build-and-lint: 13 | jobs: 14 | - build-and-lint 15 | -------------------------------------------------------------------------------- /src/docs/content/serverVars/mysqlLogFileFormat.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 11 3 | name: 'mysql_log_file_format' 4 | --- 5 | Sets the log file format, relative to the working directory of the server. If `mysql_debug` is not set to File or FileAndConsole, 6 | then this option is useless. `%s` is replaced with the name of the resource, `%d` is replaced by a timestamp. 7 | (Default: `%s-%d.log`) -------------------------------------------------------------------------------- /src/docs/content/configOptions/waitForConnections.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 22 3 | name: 'waitForConnections' 4 | --- 5 | Determines the pool's action when no connections are available and the limit has been reached. If `true`, 6 | the pool will queue the connection request and call it when one becomes available. If `false`, the pool 7 | will immediately call back with an error. (Default: `true`) -------------------------------------------------------------------------------- /src/docs/content/pages/gui&devTogglePrint.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 55 3 | --- 4 | 5 | #### Toggle Debug Print 6 | 7 | Given you have admin rights, you can use the command `mysql:debug` which flips interally the value 8 | for `mysql_debug` to `1` or `0`, so it enables you to turn on the debug prints 9 | to the console or a file, or both given your settings for `mysql_debug_output`. 10 | -------------------------------------------------------------------------------- /src/docs/content/serverVars/mysqlLogLevel.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 10 3 | name: 'mysql_log_level' 4 | --- 5 | This variable gives control over what goes to the console, and what does not. Add the numbers to get the value to set it to. 6 | 1: Info, 2: Success, 4: Warning, 8: Error. For example you wanted only Info's and Error's appearing in the server console, you would set it to 9. 7 | (Default: `15`) -------------------------------------------------------------------------------- /src/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: false, 3 | theme: { 4 | fontFamily: { 5 | sans: ['Fira Sans', 'sans-serif'], 6 | }, 7 | extend: { 8 | backgroundOpacity: { 9 | 10: '0.1', 10 | }, 11 | margin: { 12 | '-2px': '-2px', 13 | }, 14 | }, 15 | }, 16 | variants: {}, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /ui/index.html: -------------------------------------------------------------------------------- 1 | Vue App
-------------------------------------------------------------------------------- /src/docs/content/serverVars/mysqlDebug.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 1 3 | name: 'mysql_debug' 4 | --- 5 | Possible options are `Console`, `File`, `FileAndConsole` and `None`. 6 | In case of a file output, the file will be located in the current working directory 7 | on starting the server, named like `/-.log`. The name of the 8 | file can be changed by setting `mysql_log_file_format`. 9 | (Default: `None`) -------------------------------------------------------------------------------- /src/docs/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | $font-family-sans-serif: 'Fira Sans', sans-serif; 2 | $blue: #1976D2; 3 | $green: #4CAF50; 4 | $red: #FF5252; 5 | $yellow: #FFC107; 6 | $info: #2196F3; 7 | $secondary: #424242; 8 | $navbar-dark-color: rgba(#fff, .7); 9 | $navbar-dark-hover-color: rgba(#fff, .9); 10 | 11 | 12 | @import "~bootstrap"; 13 | @import "~bootstrap-vue"; 14 | @import '~prismjs/themes/prism.css'; 15 | -------------------------------------------------------------------------------- /src/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/essential', 8 | '@vue/airbnb', 9 | ], 10 | parserOptions: { 11 | ecmaVersion: 2020, 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/acquireTimeout.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 21 3 | name: 'acquireTimeout' 4 | --- 5 | The milliseconds before a timeout occurs during the connection acquisition. This is slightly different from `connectTimeout`, 6 | because acquiring a pool connection does not always involve making a connection. If a connection request is queued, 7 | the time the request spends in the queue does not count towards this timeout. (Default: `10000`) -------------------------------------------------------------------------------- /src/docs/src/pages/Gui.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | query { 13 | webPage(path: "/content/pages/gui-and-dev/") { 14 | path 15 | content 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/docs/src/pages/Queries.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | query { 14 | allWebPage(sortBy: "id", order: ASC, filter: { id: { in: ["31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43"] } }) { 15 | edges { 16 | node { 17 | path 18 | content 19 | } 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/docs/content/setup/setupResource.md: -------------------------------------------------------------------------------- 1 | --- 2 | activeStep: 1 3 | --- 4 | ### Install the Resource 5 | 6 | After you have installed a database, you will have to add the resource to the server. To do this, first 7 | [download](https://github.com/brouznouf/fivem-mysql-async/releases) the `Source code (zip)` 8 | then extract the contents to the `/resources/` folder of your server configuration and rename the folder to `mysql-async`. 9 | 10 | You are done with adding the resource to your server, click on *Next* to proceed with configuring the 11 | resource and the FXServer for the connection. -------------------------------------------------------------------------------- /src/docs/src/main.js: -------------------------------------------------------------------------------- 1 | // This is the main.js file. Import global CSS and scripts here. 2 | // The Client API can be used here. Learn more: gridsome.org/docs/client-api 3 | 4 | import DefaultLayout from '~/layouts/Default.vue'; 5 | import '~/styles/index.scss'; 6 | 7 | export default function (Vue , { head }) { 8 | // Set default layout as a global component 9 | Vue.component('Layout', DefaultLayout); 10 | 11 | head.link.push({ 12 | rel: 'stylesheet', 13 | href: 'https://fonts.googleapis.com/css2?family=Fira+Sans:ital,wght@0,400;0,500;0,700;1,400&display=swap', 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /src/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "private": true, 4 | "scripts": { 5 | "build": "gridsome build", 6 | "develop": "gridsome develop", 7 | "explore": "gridsome explore", 8 | "deploy": "gh-pages -d dist" 9 | }, 10 | "dependencies": { 11 | "@gridsome/remark-prismjs": "^0.3.0", 12 | "@gridsome/source-filesystem": "^0.6.2", 13 | "@gridsome/transformer-remark": "^0.6.1", 14 | "bootstrap-vue": "^2.15.0", 15 | "gridsome": "^0.7.0" 16 | }, 17 | "devDependencies": { 18 | "gh-pages": "^3.1.0", 19 | "sass": "^1.26.9", 20 | "sass-loader": "^9.0.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/docs/content/pages/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 21 3 | --- 4 | ## Configuration 5 | 6 | *mysql-async* is configured by setting `set mysql_connection_string "[string]"`. The connection string can either be formatted like an url: 7 | ``` 8 | set mysql_connection_string "mysql://user:password@host/database?charset=utf8mb4" 9 | ``` 10 | Here options are chained `&`. The other option is to to use an option string where each variable is seperated by an `;`, which would look like: 11 | ``` 12 | set mysql_connection_string "database=mysqlasync;charset=utf8mb4" 13 | ``` 14 | The configuration options available for these strings are listed below. 15 | -------------------------------------------------------------------------------- /src/docs/gridsome.server.js: -------------------------------------------------------------------------------- 1 | // Server API makes it possible to hook into various parts of Gridsome 2 | // on server-side and add custom data to the GraphQL data layer. 3 | // Learn more: https://gridsome.org/docs/server-api/ 4 | 5 | // Changes here require a server restart. 6 | // To restart press CTRL + C in terminal and run `gridsome develop` 7 | 8 | module.exports = function (api) { 9 | api.loadSource(({ addCollection }) => { 10 | // Use the Data Store API here: https://gridsome.org/docs/data-store-api/ 11 | }) 12 | 13 | api.createPages(({ createPage }) => { 14 | // Use the Pages API here: https://gridsome.org/docs/pages-api/ 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: GHMatti 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/docs/content/configOptions/bigNumberStrings.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 14 3 | name: 'bigNumberStrings' 4 | --- 5 | Enabling both `supportBigNumbers` and `bigNumberStrings` forces big numbers (BIGINT and DECIMAL columns) 6 | to be always returned as JavaScript String objects (Default: `false`). 7 | 8 | Enabling `supportBigNumbers` but leaving `bigNumberStrings` disabled will return big numbers as String objects 9 | only when they cannot be accurately represented with 10 | [JavaScript Number objects](http://ecma262-5.com/ELS5_HTML.htm#Section_8.5) (which happens when they exceed 11 | the [-253, +253] range), otherwise they will be returned as Number objects. This option is ignored if 12 | `supportBigNumbers` is disabled. -------------------------------------------------------------------------------- /src/docs/content/pages/setupResource.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 16 3 | --- 4 | #### Installing the Resource 5 | 6 | After you have installed a database, you will have to add the resource to the server. To do this, first [download](https://github.com/brouznouf/fivem-mysql-async/releases) the *Source Code (zip)* then extract the contents to the /resources/ folder of your server configuration. 7 | 8 | To learn more about configuring your server follow this [Link](https://docs.fivem.net/docs/server-manual/setting-up-a-server/) to the FiveM Documentation about the step-by-step guide on setting up FXServer. 9 | 10 | After the resource has been extracted you will need to add `ensure mysql-async` to your server configuration, and proceed with configuring the resource. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: GHMatti 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Please provide a brief script that causes the error. 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Screenshots / Logs** 20 | If applicable, add screenshots and Logs to help explain your problem. 21 | 22 | **Software:** 23 | - OS: [e.g. Windows 10] 24 | - Version of the resource [e.g. 22] 25 | - Database Version [e.g. MariaDB 10.4 or MySQL 8.0] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | -------------------------------------------------------------------------------- /src/postcss.config.js: -------------------------------------------------------------------------------- 1 | const IN_PRODUCTION = process.env.NODE_ENV === 'production'; 2 | 3 | module.exports = { 4 | plugins: [ 5 | require('tailwindcss'), 6 | require('autoprefixer'), 7 | require('@fullhuman/postcss-purgecss')({ 8 | content: ['./template/**/*.html', './ui/**/*.vue', './vendor/ghmattimysql/packages/ghmattimysql-ui/src/components/**/*.vue'], 9 | defaultExtractor(content) { 10 | const contentWithoutStyleBlocks = content.replace(//gi, ''); 11 | return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || []; 12 | }, 13 | whitelist: [], 14 | whitelistPatterns: [/-(leave|enter|appear)(|-(to|from|active))$/, /^(?!(|.*?:)cursor-move).+-move$/, /^router-link(|-exact)-active$/, /data-v-.*/], 15 | }), 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'adamant' 2 | game 'common' 3 | 4 | name 'mysql-async' 5 | description 'MySQL Middleware for lua.' 6 | author 'Joel Wurtz & Matthias Mandelartz' 7 | version '3.3.2' 8 | url 'https://github.com/brouznouf/fivem-mysql-async' 9 | 10 | server_script 'mysql-async.js' 11 | client_script 'mysql-async-client.lua' 12 | 13 | files { 14 | 'ui/index.html', 15 | 'ui/js/app.js', 16 | 'ui/css/app.css', 17 | 'ui/fonts/fira-sans-v9-latin-700.woff', 18 | 'ui/fonts/fira-sans-v9-latin-700.woff2', 19 | 'ui/fonts/fira-sans-v9-latin-italic.woff', 20 | 'ui/fonts/fira-sans-v9-latin-italic.woff2', 21 | 'ui/fonts/fira-sans-v9-latin-regular.woff', 22 | 'ui/fonts/fira-sans-v9-latin-regular.woff2', 23 | 'ui/fonts/MaterialIcons-Regular.eot', 24 | 'ui/fonts/MaterialIcons-Regular.ttf', 25 | 'ui/fonts/MaterialIcons-Regular.woff', 26 | 'ui/fonts/MaterialIcons-Regular.woff2', 27 | } 28 | 29 | ui_page 'ui/index.html' 30 | -------------------------------------------------------------------------------- /src/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const baseConfig = { 4 | mode: 'production', 5 | target: 'node', 6 | optimization: { 7 | minimize: false, 8 | }, 9 | resolve: { 10 | extensions: [ '.ts', '.js' ], 11 | }, 12 | module: { 13 | rules: [ 14 | { 15 | test: /.ts$/, 16 | use: { 17 | loader: 'babel-loader', 18 | options: { 19 | presets: [ 20 | [ 21 | "@babel/preset-env", 22 | { 23 | targets: { 24 | node: true, 25 | }, 26 | }, 27 | ], 28 | ], 29 | plugins: ["@babel/plugin-transform-typescript"], 30 | }, 31 | }, 32 | }, 33 | ], 34 | }, 35 | }; 36 | 37 | const serverConfig = { 38 | entry: './entry/server.ts', 39 | output: { 40 | filename: 'mysql-async.js', 41 | path: path.resolve(__dirname, '..'), 42 | }, 43 | ...baseConfig, 44 | }; 45 | 46 | module.exports = serverConfig; 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2017, Joel Wurtz; © 2018 - 2019 Matthias Mandelartz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 4 | documentation files (the “Software”), to deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 6 | persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 9 | Software. 10 | 11 | The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the 12 | warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or 13 | copyright holders X be liable for any claim, damages or other liability, whether in an action of contract, tort or 14 | otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software. 15 | -------------------------------------------------------------------------------- /src/docs/src/layouts/Default.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Introduction 2 | 3 | This mysql-async Library for FiveM intends to provide function to connect to a MySQL in a Sync and Async way. 4 | 5 | ### Documentation 6 | 7 | Check out https://brouznouf.github.io/fivem-mysql-async/ for a complete documentation. 8 | 9 | ### Questions 10 | For help and support questions, please use [Discord](https://discord.gg/AXcxRjt). I would like to keep the issues in this repository for bugs and feature requests only. 11 | 12 | ### Supporting 13 | If you wish to support GHMatti for whatever reason use the **[Patreon](https://www.patreon.com/GHMatti)**. 14 | 15 | ### Issues 16 | Make sure you provide all information possible when reporting an issue. 17 | 18 | ### Changelog 19 | For a detailed changelog either check the commits or read https://github.com/brouznouf/fivem-mysql-async/releases 20 | 21 | ### Contributing 22 | Help to expand sensibly on the middleware is always welcome. 23 | 24 | ### Features 25 | 26 | * Async / Sync. 27 | * It uses the https://github.com/mysqljs/mysql library to provide a connection to your mysql server. 28 | * Create and close a connection for each query, the underlying library use a connection pool so only the 29 | mysql auth is done each time, old tcp connections are keeped in memory for performance reasons. 30 | -------------------------------------------------------------------------------- /src/docs/gridsome.config.js: -------------------------------------------------------------------------------- 1 | // This is where project configuration and plugin options are located. 2 | // Learn more: https://gridsome.org/docs/config 3 | 4 | // Changes here require a server restart. 5 | // To restart press CTRL + C in terminal and run `gridsome develop` 6 | const remark = { 7 | plugins: [ 8 | '@gridsome/remark-prismjs', 9 | ] 10 | }; 11 | 12 | module.exports = { 13 | siteName: 'mysql-async Documentation', 14 | pathPrefix: '/fivem-mysql-async', 15 | plugins: [ 16 | { 17 | use: '@gridsome/source-filesystem', 18 | options: { 19 | path: 'content/pages/**/*.md', 20 | typeName: 'WebPage', 21 | remark, 22 | }, 23 | }, 24 | { 25 | use: '@gridsome/source-filesystem', 26 | options: { 27 | path: 'content/configOptions/**/*.md', 28 | typeName: 'ConfigOption', 29 | remark, 30 | }, 31 | }, 32 | { 33 | use: '@gridsome/source-filesystem', 34 | options: { 35 | path: 'content/serverVars/**/*.md', 36 | typeName: 'ServerVar', 37 | remark, 38 | }, 39 | }, 40 | { 41 | use: '@gridsome/source-filesystem', 42 | options: { 43 | path: 'content/Setup/**/*.md', 44 | typeName: 'SetupStep', 45 | remark, 46 | }, 47 | }, 48 | ], 49 | } 50 | -------------------------------------------------------------------------------- /src/docs/content/pages/gui&dev.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 51 3 | --- 4 | 5 | ## GUI & Dev 6 | 7 | With administration rights on your server, if you are unsure how to get those check the 8 | [step-by-step guide on setting up FXServer](https://docs.fivem.net/docs/server-manual/setting-up-a-server/), 9 | you can type in the command `mysql` into the console to open the GUI. You can open that console via the F8 key. 10 | It should show you a concise summary of how your server is doing. 11 | 12 | The first tab shows you a time-resolved graph showing how long the queries took time in a five minute interval. 13 | As a general rule of thumb the server should not spend more than 300,000ms querying the database. It could become especially problematic 14 | if the amount of queries is at that point lower than 6,000, at which point your queries are likely too slow and 15 | are in need of optimization. 16 | 17 | The second tab shows you the same as the first tab, but instead of the queries being time-resolved they are resolved by the resources 18 | which trigger them. So you can see which resources ask for the largest amount of database time. 19 | 20 | The last slow query tab lists the 21 slowest queries. If they are all below the max-limit in [table for MySQL servers](#setup), 21 | then there is no need to panic, it might be database and not a query related issue. 22 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql-async", 3 | "version": "3.3.2", 4 | "description": "fivem-mysql-async", 5 | "private": true, 6 | "scripts": { 7 | "build": "webpack --progress", 8 | "build:ui": "vue-cli-service build ./entry/nui.js", 9 | "lint:ui": "vue-cli-service lint ./entry/nui.js", 10 | "lint": "eslint '**/*.js'" 11 | }, 12 | "contributors": [ 13 | "Joel Wurtz", 14 | "Matthias Mandelartz" 15 | ], 16 | "license": "MIT", 17 | "dependencies": { 18 | "autoprefixer": "^9.8.4", 19 | "chart.js": "^2.9.3", 20 | "material-design-icons-iconfont": "^5.0.1", 21 | "mysql": "^2.18.1", 22 | "tailwindcss": "^1.4.6", 23 | "vue": "^2.6.11" 24 | }, 25 | "devDependencies": { 26 | "@babel/core": "^7.10.4", 27 | "@babel/plugin-transform-typescript": "^7.10.4", 28 | "@babel/preset-env": "^7.10.4", 29 | "@citizenfx/client": "^1.0.2624-1", 30 | "@citizenfx/server": "^1.0.2624-1", 31 | "@fullhuman/postcss-purgecss": "^2.3.0", 32 | "@fullhuman/vue-cli-plugin-purgecss": "^2.2.0", 33 | "@types/mysql": "^2.15.14", 34 | "@types/node": "^14.0.14", 35 | "@vue/cli-plugin-eslint": "^4.4.6", 36 | "@vue/cli-service": "^4.4.6", 37 | "@vue/eslint-config-airbnb": "^5.1.0", 38 | "babel-loader": "^8.1.0", 39 | "eslint": "^6.8.0", 40 | "eslint-plugin-vue": "^6.2.2", 41 | "npm-run-all": "^4.1.5", 42 | "sass": "^1.26.9", 43 | "sass-loader": "^9.0.1", 44 | "vue-template-compiler": "^2.6.11", 45 | "webpack": "^4.43.0", 46 | "webpack-cli": "^3.3.12" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/docs/src/components/Benchmark.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 50 | -------------------------------------------------------------------------------- /src/docs/src/pages/Config.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 35 | query { 36 | allWebPage(sortBy: "id", order: ASC, filter: { id: { in: ["21", "22", "23", "24", "25", "26", "27", "28", "29", "30"] } }) { 37 | edges { 38 | node { 39 | path 40 | content 41 | } 42 | } 43 | } 44 | allConfigOption(sortBy: "id", order: ASC) { 45 | edges { 46 | node { 47 | path 48 | name 49 | content 50 | } 51 | } 52 | } 53 | allServerVar(sortBy: "id", order: ASC) { 54 | edges { 55 | node { 56 | path 57 | name 58 | content 59 | } 60 | } 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/docs/content/pages/transactions.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 41 3 | --- 4 | 5 | ## Transactions 6 | 7 | A transaction will only commit all queries to the database, if all queries to the database succeed. If one of them fails, no changes to the database will be made. This can be easily used when e.g. transfering money, making sure that the money field is positive. A transaction would fail if someone would attempt to have negative cash, so that no money would be transfered. 8 | 9 | Since the transaction will either fail or succeed, the callback of the function will either answer with true or false depending on if the transaction succeeded. If it fails an error message will be printed, but it is an intended one, since the commit to the database would be likely unwanted. 10 | 11 | The following example shows the same transaction being done twice in different ways. 12 | 13 | ```lua 14 | MySQL.Async.transaction({ 15 | 'UPDATE users SET cash = cash - @transfer WHERE id = @senderId', 16 | 'UPDATE users SET cash = cash + @transfer WHERE id = @recipientId' 17 | }, 18 | { ['transfer'] = amount, ['senderId'] = senderId, ['recipientId'] = recipientId }, 19 | function(success) 20 | print(success) 21 | end 22 | ) 23 | --[[ 24 | prints: 25 | 26 | true or false, depending on if cash goes negative or not. 27 | ]]-- 28 | ``` 29 | 30 | ```lua 31 | MySQL.Async.transaction({ 32 | { 33 | query = 'UPDATE users SET cash = cash - @transfer WHERE id = @senderId', 34 | values = { ['transfer'] = amount, ['senderId'] = senderId }, 35 | }, 36 | { 37 | query = 'UPDATE users SET cash = cash + @transfer WHERE id = @recipientId', 38 | values = { ['transfer'] = amount, ['recipientId'] = recipientId }, 39 | }, 40 | }, 41 | function(success) 42 | print(success) 43 | end 44 | ) 45 | --[[ 46 | prints: 47 | 48 | true or false, depending on if cash goes negative or not. 49 | ]]-- 50 | ``` -------------------------------------------------------------------------------- /example.lua: -------------------------------------------------------------------------------- 1 | --executed = 0 2 | --received = 0 3 | -- 4 | --local function Loop() 5 | -- SetTimeout(2, function () 6 | ---- MySQL.Sync.fetchAll('WRONG SQL QUERY', {}) 7 | -- 8 | -- MySQL.Sync.fetchScalar('SELECT @parameters', { 9 | -- ['@parameters'] = 'string' 10 | -- }) 11 | -- 12 | -- executed = executed + 1 13 | -- 14 | -- MySQL.Async.fetchAll('SELECT "hello2" as world', {}, function(result) 15 | -- received = received + 1 16 | -- end) 17 | -- 18 | -- if executed % 100 == 0 then 19 | -- print(received .. "/" .. executed) 20 | -- end 21 | -- 22 | -- Loop() 23 | -- end) 24 | --end 25 | -- 26 | --AddEventHandler('onMySQLReady', function () 27 | -- Loop() 28 | --end) 29 | 30 | MySQL.ready(function () 31 | print(MySQL.Sync.fetchScalar('SELECT @parameters', { 32 | ['@parameters'] = 1 33 | })) 34 | 35 | print(MySQL.Sync.fetchScalar('SELECT @parameters', { 36 | ['@parameters'] = 'string' 37 | })) 38 | 39 | MySQL.Async.fetchScalar('SELECT NOW() as world', {}, function(result) 40 | print(result) 41 | end) 42 | 43 | MySQL.Async.execute('SELECT SLEEP(5)', nil, function() 44 | print("1") 45 | end) 46 | MySQL.Async.execute('SELECT SLEEP(4)', nil, function() 47 | print("2") 48 | end) 49 | MySQL.Async.execute('SELECT SLEEP(3)', {}, function() 50 | print("3") 51 | end) 52 | MySQL.Async.execute('SELECT SLEEP(2)', nil, function() 53 | print("4") 54 | end) 55 | MySQL.Async.execute('SELECT SLEEP(1)', nil, function() 56 | print("5") 57 | end) 58 | 59 | print(MySQL.Sync.fetchScalar("SELECT money FROM users WHERE id = 'yolo' ")) 60 | 61 | MySQL.Async.fetchAll("SELECT money FROM users WHERE id = 'yolo' ", {}, function (result) 62 | print(#result) 63 | end) 64 | 65 | print(MySQL.Sync.fetchAll('SELECT "hello1" as world', {})[1].world) 66 | 67 | MySQL.Async.fetchAll('SELECT "hello2" as world', {}, function(result) 68 | print(result[1].world) 69 | end) 70 | 71 | print(MySQL.Sync.fetchScalar('SELECT "hello3" as world', {})) 72 | 73 | MySQL.Async.fetchScalar('SELECT "hello4" as world', {}, function(result) 74 | print(result) 75 | end) 76 | 77 | print(json.encode(MySQL.Sync.fetchScalar('SELECT null', {}))) 78 | 79 | MySQL.Async.fetchScalar('SELECT null', {}, function(result) 80 | print(result) 81 | end) 82 | 83 | MySQL.Sync.fetchAll('WRONG SQL QUERY', {}) 84 | end) 85 | -------------------------------------------------------------------------------- /src/docs/src/pages/Index.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 57 | 58 | 59 | query { 60 | allSetupStep(sortBy: "activeStep", order: ASC) { 61 | edges { 62 | node { 63 | path 64 | activeStep 65 | content 66 | } 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/docs/content/pages/queries.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 31 3 | --- 4 | ## Queries 5 | 6 | All query types in mysql-async can be fired using either *Sync* or *Async* methods, which can be retrieved from the MySQL object. The last parameter of an Async function is always the callback, the argument of the callback gets returned by *Sync* functions. 7 | 8 | Contrary to older *Sync* implementations, these functions are safe to use, since they are non-blocking and just wrappers around the *Async* calls. But for a possible migration to other Database implementations, the use of the Sync functions should be discouraged. 9 | 10 | ### MySQL.ready 11 | 12 | You need to encapsulate your code into `MySQL.ready` to be sure that the mod will be available and initialized before your first request. In subsequent examples the `MySQL.ready` function will not be shown, and it is expected that the code is encapsulated. 13 | ```lua 14 | MySQL.ready(function () 15 | print(MySQL.Sync.fetchScalar('SELECT @parameters', { 16 | ['@parameters'] = 'string' 17 | })) 18 | end) 19 | --[[ 20 | prints: 21 | 22 | string 23 | ]]-- 24 | ``` 25 | 26 | ### execute 27 | 28 | Execute a mysql query which should not send any result (like a Insert / Delete / Update), and will return the number of affected rows. 29 | 30 | ```lua 31 | MySQL.Async.execute('INSERT INTO users_log (x, y, z, playerId) VALUES (@x, @y, @z, @id)', 32 | { ['x'] = pos.x, ['y'] = pos.y, ['z'] = pos.z, ['id'] = player.id }, 33 | function(affectedRows) 34 | print(affectedRows) 35 | end 36 | ) 37 | --[[ 38 | prints: 39 | 40 | 1 41 | ]]-- 42 | ``` 43 | 44 | ### fetchAll 45 | 46 | Fetch results from MySQL and returns them in the form of an Array of Objects: 47 | 48 | ```lua 49 | MySQL.Async.fetchAll('SELECT * FROM users WHERE id = @id', { ['@id'] = playerId }, function(result) 50 | print(json.encode(result)) 51 | end) 52 | --[[ 53 | prints: 54 | 55 | [{ 56 | "id": 95585726093402110, 57 | "cash": 0, 58 | "bank": 0, 59 | "skin": "{}", 60 | "online": true, 61 | "lastSeen": 1590656804000 62 | }] 63 | ]]-- 64 | ``` 65 | 66 | ### fetchScalar 67 | 68 | Fetch the first field of the first row in a query: 69 | ```lua 70 | MySQL.Async.fetchScalar('SELECT COUNT(1) FROM users', {}, function(result) 71 | print(result) 72 | end) 73 | --[[ 74 | prints: 75 | 76 | 15 77 | ]]-- 78 | ``` 79 | 80 | ### insert 81 | 82 | Returns the last insert id of the inserted item. Needs an auto-incremented primary key to work. 83 | 84 | ```lua 85 | MySQL.Async.insert('INSERT INTO users_log (x, y, z, playerId) VALUES (@x, @y, @z, @id)', 86 | { ['x'] = pos.x, ['y'] = pos.y, ['z'] = pos.z, ['id'] = player.id }, 87 | function(insertId) 88 | print(insertId) 89 | end 90 | ) 91 | --[[ 92 | prints: 93 | 94 | 1137 95 | ]]-- 96 | ``` 97 | 98 | ### store 99 | 100 | The store export should be used for storing query strings, when a lot of queries are expected to be triggered at once. The idea behind this feature is, that while recieving data puts stress on your server infrastructure, so does sending data. And the biggest polluter for this resource is sending overly long and complicated query strings. 101 | 102 | While the server is running you want to minimize the impact of sending a lot of queries at once puts on your architecture, thus you can already store these queries ahead of time, and just pass the id returned by the callback function and pass the parameters for these queries along. 103 | 104 | ```lua 105 | insertUserLog = -1 106 | MySQL.Async.store("INSERT INTO users_log SET ?", function(storeId) insertUserLog = storeId end) 107 | -- ... 108 | MySQL.Async.insert(insertUserLog, { 109 | { ['x'] = pos.x, ['y'] = pos.y, ['z'] = pos.z, ['playerId'] = player.id } 110 | }, function(response) 111 | print(insertId) 112 | end) 113 | ``` 114 | 115 | This works like the example above, but the query string does not need to be reset and is a bit more elegant in the writing. 116 | -------------------------------------------------------------------------------- /mysql-async-client.lua: -------------------------------------------------------------------------------- 1 | local isNuiActive = false 2 | 3 | function setNuiActive(booleanOrNil) 4 | local boolean = true 5 | if booleanOrNil ~= nil then boolean = booleanOrNil end 6 | if boolean ~= isNuiActive then 7 | if boolean then TriggerServerEvent('mysql-async:request-data') end 8 | isNuiActive = boolean 9 | SendNUIMessage({ type = 'onToggleShow' }) 10 | SetNuiFocus(boolean, boolean) 11 | end 12 | end 13 | 14 | RegisterCommand('mysql', function() 15 | setNuiActive() 16 | end, true) 17 | 18 | RegisterNUICallback('close-explorer', function() 19 | setNuiActive(false) 20 | end) 21 | 22 | CreateThread(function() 23 | if isNuiActive then TriggerServerEvent('mysql-async:request-data') end 24 | Wait(300000) 25 | end) 26 | 27 | function isArray(t) 28 | local i = 0 29 | for _ in pairs(t) do 30 | i = i + 1 31 | if t[i] == nil then return false end 32 | end 33 | return true 34 | end 35 | 36 | function map(t, callback) 37 | local newTable = {} 38 | for i = 1, #t do 39 | newTable[i] = callback(t[i], i) 40 | end 41 | return newTable 42 | end 43 | 44 | function filter(t, callback) 45 | local newTable = {} 46 | for i = 1, #t do 47 | if callback(t[i], i) then 48 | table.insert(newTable, t[i]) 49 | end 50 | end 51 | return newTable 52 | end 53 | 54 | RegisterNetEvent('mysql-async:update-resource-data') 55 | AddEventHandler('mysql-async:update-resource-data', function (resourceData) 56 | local arrayToSortAndMap = {} 57 | for resource, data in pairs(resourceData) do 58 | table.insert(arrayToSortAndMap, { 59 | resource = resource, 60 | queryTime = data.totalExecutionTime, 61 | count = data.queryCount, 62 | }) 63 | end 64 | if #arrayToSortAndMap > 0 then 65 | table.sort(arrayToSortAndMap, function(a, b) return a.queryTime > b.queryTime end) 66 | local len = #arrayToSortAndMap 67 | arrayToSortAndMap = filter(arrayToSortAndMap, function(_, index) return index > len - 30 end) 68 | table.sort(arrayToSortAndMap, function(a, b) return a.resource:upper() > b.resource:upper() end) 69 | SendNUIMessage({ 70 | type = 'onResourceLabels', 71 | resourceLabels = map(arrayToSortAndMap, function(el) return el.resource end), 72 | }) 73 | SendNUIMessage({ 74 | type = 'onResourceData', 75 | resourceData = { 76 | { data = map(arrayToSortAndMap, function(el) return el.queryTime end) }, 77 | { data = map(arrayToSortAndMap, function(el) if el.count > 0 then return el.queryTime / el.count end return 0 end) }, 78 | { data = map(arrayToSortAndMap, function(el) return el.count end) }, 79 | }, 80 | }) 81 | end 82 | end) 83 | 84 | RegisterNetEvent('mysql-async:update-time-data') 85 | AddEventHandler('mysql-async:update-time-data', function (timeData) 86 | local timeArray = {} 87 | if isArray(timeData) then 88 | local len = #timeData 89 | timeArray = filter(timeData, function(_, index) return index > len - 30 end) 90 | end 91 | if #timeArray > 0 then 92 | SendNUIMessage({ 93 | type = 'onTimeData', 94 | timeData = { 95 | { data = map(timeArray, function(el) return el.totalExecutionTime end) }, 96 | { data = map(timeArray, function(el) if el.queryCount > 0 then return el.totalExecutionTime / el.queryCount end return 0 end) }, 97 | { data = map(timeArray, function(el) return el.queryCount end) }, 98 | } 99 | }) 100 | end 101 | end) 102 | 103 | RegisterNetEvent('mysql-async:update-slow-queries') 104 | AddEventHandler('mysql-async:update-slow-queries', function(slowQueryData) 105 | local slowQueries = slowQueryData 106 | for i = 1, #slowQueries do 107 | slowQueries[i].queryTime = math.floor(slowQueries[i].queryTime * 100 + 0.5) / 100 108 | end 109 | SendNUIMessage({ 110 | type = 'onSlowQueryData', 111 | slowQueries = slowQueries, 112 | }); 113 | end) 114 | 115 | RegisterNetEvent('mysql-async:update-status') 116 | AddEventHandler('mysql-async:update-status', function(statusData) 117 | SendNUIMessage({ 118 | type = 'onStatusData', 119 | status = statusData, 120 | }); 121 | end) 122 | 123 | RegisterNetEvent('mysql-async:update-variables') 124 | AddEventHandler('mysql-async:update-variables', function(variableData) 125 | SendNUIMessage({ 126 | type = 'onVariableData', 127 | variables = variableData, 128 | }); 129 | end) 130 | 131 | RegisterNUICallback('request-server-status', function() 132 | TriggerServerEvent('mysql-async:request-server-status') 133 | end) 134 | 135 | RegisterNetEvent('mysql-async:get-table-schema') 136 | AddEventHandler('mysql-async:get-table-schema', function(tableName, schema) 137 | SendNUIMessage({ 138 | type = 'onTableSchema', 139 | tableName = tableName, 140 | schema = schema, 141 | }); 142 | end) 143 | 144 | RegisterNUICallback('request-table-schema', function(tableName) 145 | TriggerServerEvent('mysql-async:request-table-schema', tableName) 146 | end) 147 | -------------------------------------------------------------------------------- /src/entry/server.ts: -------------------------------------------------------------------------------- 1 | import { OkPacket } from 'mysql'; 2 | import { safeInvoke } from '../vendor/ghmattimysql/packages/ghmattimysql/src/server/utility'; 3 | import CFXCallback from '../vendor/ghmattimysql/packages/ghmattimysql/src/server/types/cfxCallback'; 4 | import { OutputDestination } from '../vendor/ghmattimysql/packages/ghmattimysql/src/server/logger/loggerConfig'; 5 | import Server from '../vendor/ghmattimysql/packages/ghmattimysql/src/server'; 6 | import getConfig from '../vendor/ghmattimysql/packages/ghmattimysql/src/server/utility/getConfig'; 7 | 8 | const defaultCfg = { 9 | host: '127.0.0.1', 10 | user: 'root', 11 | password: '', 12 | database: 'fivem', 13 | supportBigNumbers: true, 14 | multipleStatements: true, 15 | }; 16 | 17 | // Switch to just connecting immediately 18 | const config = { ...defaultCfg, ...getConfig() }; 19 | const server = new Server(config, { tag: 'mysql-async' }); 20 | 21 | let isReady = false; 22 | global.exports('is_ready', () => isReady); 23 | 24 | on('onResourceStart', (resourcename) => { 25 | // avoid old bugs 26 | if (resourcename === 'mysql-async') { 27 | emit('onMySQLReady'); 28 | isReady = true; 29 | if ((config).keepAlive) { 30 | setInterval(() => { 31 | server.execute('SELECT 1', [], null, 'mysql-async:keepAlive'); 32 | }, (config).keepAlive * 1000); 33 | } 34 | } 35 | }); 36 | 37 | global.exports('mysql_execute', (query: string | number, parameters?: any | CFXCallback, callback?: any | CFXCallback, resource?: string): void => { 38 | const invokingResource = resource || GetInvokingResource(); 39 | server.execute(query, parameters, callback, invokingResource).then(([result, cb]) => { 40 | safeInvoke(cb, (result) ? (result).affectedRows : 0); 41 | return true; 42 | }).catch(() => false); 43 | }); 44 | 45 | global.exports('mysql_fetch_all', (query: string | number, parameters?: any | CFXCallback, callback?: any | CFXCallback, resource?: string): void => { 46 | const invokingResource = resource || GetInvokingResource(); 47 | server.execute(query, parameters, callback, invokingResource).then(([result, cb]) => { 48 | safeInvoke(callback, result); 49 | return true; 50 | }).catch(() => false); 51 | }); 52 | 53 | global.exports('mysql_fetch_scalar', (query: string | number, parameters?: any | CFXCallback, callback?: any | CFXCallback, resource?: string): void => { 54 | const invokingResource = resource || GetInvokingResource(); 55 | server.execute(query, parameters, callback, invokingResource).then(([result, cb]) => { 56 | safeInvoke(cb, (result && result[0]) ? Object.values(result[0])[0] : null); 57 | return true; 58 | }).catch(() => false); 59 | }); 60 | 61 | global.exports('mysql_insert', (query: string | number, parameters?: any | CFXCallback, callback?: any | CFXCallback, resource?: string): void => { 62 | const invokingResource = resource || GetInvokingResource(); 63 | server.execute(query, parameters, callback, invokingResource).then(([result, cb]) => { 64 | safeInvoke(cb, (result) ? (result).insertId : 0); 65 | return true; 66 | }).catch(() => false); 67 | }); 68 | 69 | global.exports('mysql_transaction', (querys, values?: any | CFXCallback, callback?: CFXCallback, resource?: string) => { 70 | const invokingResource = resource || GetInvokingResource(); 71 | server.transaction(querys, values, callback, invokingResource).then(([result, cb]) => { 72 | safeInvoke(cb, result); 73 | return true; 74 | }).catch(() => false); 75 | }); 76 | 77 | global.exports('mysql_store', (query: string, callback: CFXCallback) => { 78 | const invokingResource = GetInvokingResource(); 79 | const storageId = server.queryStorage.add(query); 80 | server.logger.info(`[${invokingResource}] Stored [${storageId}] : ${query}`); 81 | safeInvoke(callback, storageId); 82 | }); 83 | 84 | RegisterCommand('mysql:debug', () => { 85 | let trace = false; 86 | if (server.logger.defaultConfig.output === OutputDestination.FileAndConsole 87 | || server.logger.defaultConfig.output === OutputDestination.Console) { 88 | server.logger.defaultConfig.output = OutputDestination.File; 89 | } else { 90 | server.logger.defaultConfig.output = OutputDestination.FileAndConsole; 91 | trace = true; 92 | } 93 | server.logger.info(`display debug: ${trace}`); 94 | }, true); 95 | 96 | onNet('mysql-async:request-data', () => { 97 | const src = source; 98 | emitNet('mysql-async:update-resource-data', src, server.profiler.profiles.resources); 99 | emitNet('mysql-async:update-time-data', src, server.profiler.profiles.executionTimes); 100 | emitNet('mysql-async:update-slow-queries', src, server.profiler.profiles.slowQueries); 101 | }); 102 | 103 | onNet('mysql-async:request-server-status', () => { 104 | const src = source; 105 | server.execute('SHOW GLOBAL STATUS', (data: unknown) => { 106 | emitNet('mysql-async:update-status', src, data); 107 | }, null, 'mysql-async').then(([result, cb]) => { 108 | cb(result); 109 | }).catch(() => false); 110 | server.execute('SHOW GLOBAL VARIABLES', (data: unknown) => { 111 | emitNet('mysql-async:update-variables', src, data); 112 | }, null, 'mysql-async').then(([result, cb]) => { 113 | cb(result); 114 | }).catch(() => false); 115 | }); 116 | -------------------------------------------------------------------------------- /ui/css/app.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}a{background-color:transparent}b,strong{font-weight:bolder}small{font-size:80%}template{display:none}ul{list-style:none;margin:0;padding:0}html{font-family:Fira Sans,sans-serif;line-height:1.5}*,:after,:before{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e2e8f0}table{border-collapse:collapse}a{color:inherit;text-decoration:inherit}canvas{display:block;vertical-align:middle}.bg-black{--bg-opacity:1;background-color:#000;background-color:rgba(0,0,0,var(--bg-opacity))}.bg-white{--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.bg-gray-300{--bg-opacity:1;background-color:#e2e8f0;background-color:rgba(226,232,240,var(--bg-opacity))}.hover\:bg-black:hover{--bg-opacity:1;background-color:#000;background-color:rgba(0,0,0,var(--bg-opacity))}.hover\:bg-white:hover{--bg-opacity:1;background-color:#fff;background-color:rgba(255,255,255,var(--bg-opacity))}.bg-opacity-50{--bg-opacity:0.5}.hover\:bg-opacity-10:hover{--bg-opacity:0.1}.border-black{--border-opacity:1;border-color:#000;border-color:rgba(0,0,0,var(--border-opacity))}.border-blue-600{--border-opacity:1;border-color:#3182ce;border-color:rgba(49,130,206,var(--border-opacity))}.border-opacity-0{--border-opacity:0}.border-opacity-25{--border-opacity:0.25}.hover\:border-opacity-50:hover{--border-opacity:0.5}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.rounded-b-md{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.border-b-2{border-bottom-width:2px}.border-b{border-bottom-width:1px}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.flex-grow{flex-grow:1}.flex-shrink-0{flex-shrink:0}.font-light{font-weight:300}.font-medium{font-weight:500}.h-4{height:1rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-12{height:3rem}.h-screen{height:100vh}.text-sm{font-size:.875rem}.text-xl{font-size:1.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mt-1{margin-top:.25rem}.mr-2{margin-right:.5rem}.mb-2{margin-bottom:.5rem}.mr-8{margin-right:2rem}.-mb-2px{margin-bottom:-2px}.max-w-screen-xl{max-width:1280px}.overflow-y-scroll{overflow-y:scroll}.p-2{padding:.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.shadow-2xl{box-shadow:0 25px 50px -12px rgba(0,0,0,.25)}.table-auto{table-layout:auto}.text-left{text-align:left}.text-center{text-align:center}.text-black{--text-opacity:1;color:#000;color:rgba(0,0,0,var(--text-opacity))}.text-gray-100{--text-opacity:1;color:#f7fafc;color:rgba(247,250,252,var(--text-opacity))}.text-blue-600{--text-opacity:1;color:#3182ce;color:rgba(49,130,206,var(--text-opacity))}.text-opacity-25{--text-opacity:0.25}.text-opacity-50{--text-opacity:0.5}.text-opacity-100{--text-opacity:1}.hover\:text-opacity-75:hover{--text-opacity:0.75}.hover\:text-opacity-100:hover{--text-opacity:1}.uppercase{text-transform:uppercase}.w-4{width:1rem}.w-6{width:1.5rem}.w-full{width:100%}.transition{transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}@font-face{font-family:Fira Sans;font-style:normal;font-weight:400;src:url(../fonts/fira-sans-v9-latin-regular.woff) format("woff"),url(../fonts/fira-sans-v9-latin-regular.woff2) format("woff2")}@font-face{font-family:Fira Sans;font-style:italic;font-weight:400;src:url(../fonts/fira-sans-v9-latin-italic.woff) format("woff"),url(../fonts/fira-sans-v9-latin-italic.woff2) format("woff2")}@font-face{font-family:Fira Sans;font-style:normal;font-weight:700;src:url(../fonts/fira-sans-v9-latin-700.woff) format("woff"),url(../fonts/fira-sans-v9-latin-700.woff2) format("woff2")}@font-face{font-family:Material Icons;font-style:normal;font-weight:400;font-display:block;src:url(../fonts/MaterialIcons-Regular.eot);src:local("☺"),url(../fonts/MaterialIcons-Regular.woff2) format("woff2"),url(../fonts/MaterialIcons-Regular.woff) format("woff"),url(../fonts/MaterialIcons-Regular.ttf) format("truetype")}.material-icons{font-family:Material Icons;font-weight:400;font-style:normal;font-size:24px;display:inline-block;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:"liga"}.material-icons.apps:before{content:"\e5c3"}.material-icons.arrow_back_ios:before{content:"\e5e0"}.material-icons.arrow_downward:before{content:"\e5db"}.material-icons.arrow_forward_ios:before{content:"\e5e1"}.material-icons.arrow_upward:before{content:"\e5d8"}.material-icons.block:before{content:"\e14b"}.material-icons.class:before{content:"\e86e"}.material-icons.close:before{content:"\e5cd"}.material-icons.event:before{content:"\e878"}.material-icons.filter:before{content:"\e3d3"}.material-icons.height:before{content:"\ea16"}.material-icons.label:before{content:"\e892"}.material-icons.map:before{content:"\e55b"}.material-icons.message:before{content:"\e0c9"}.material-icons.pages:before{content:"\e7f9"}.material-icons.settings_applications:before{content:"\e8b9"}.material-icons.slow_motion_video:before{content:"\e068"}.material-icons.sort:before{content:"\e164"}.material-icons.storage:before{content:"\e1db"}.material-icons.style:before{content:"\e41d"}.material-icons.tab:before{content:"\e8d8"}.material-icons.timeline:before{content:"\e922"}.material-icons.title:before{content:"\e264"}.material-icons.update:before{content:"\e923"}.material-icons.watch:before{content:"\e334"}.material-icons.work:before{content:"\e8f9"} -------------------------------------------------------------------------------- /lib/MySQL.lua: -------------------------------------------------------------------------------- 1 | MySQL = { 2 | Async = {}, 3 | Sync = {}, 4 | } 5 | 6 | local function safeParameters(params) 7 | if nil == params then 8 | return {[''] = ''} 9 | end 10 | 11 | assert(type(params) == "table", "A table is expected") 12 | 13 | if next(params) == nil then 14 | return {[''] = ''} 15 | end 16 | 17 | return params 18 | end 19 | 20 | --- 21 | -- Execute a query with no result required, sync version 22 | -- 23 | -- @param query 24 | -- @param params 25 | -- 26 | -- @return int Number of rows updated 27 | -- 28 | function MySQL.Sync.execute(query, params) 29 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 30 | 31 | local res = 0 32 | local finishedQuery = false 33 | exports['mysql-async']:mysql_execute(query, safeParameters(params), function (result) 34 | res = result 35 | finishedQuery = true 36 | end) 37 | repeat Citizen.Wait(0) until finishedQuery == true 38 | return res 39 | end 40 | --- 41 | -- Execute a query and fetch all results in an sync way 42 | -- 43 | -- @param query 44 | -- @param params 45 | -- 46 | -- @return table Query results 47 | -- 48 | function MySQL.Sync.fetchAll(query, params) 49 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 50 | 51 | local res = {} 52 | local finishedQuery = false 53 | exports['mysql-async']:mysql_fetch_all(query, safeParameters(params), function (result) 54 | res = result 55 | finishedQuery = true 56 | end) 57 | repeat Citizen.Wait(0) until finishedQuery == true 58 | return res 59 | end 60 | 61 | --- 62 | -- Execute a query and fetch the first column of the first row, sync version 63 | -- Useful for count function by example 64 | -- 65 | -- @param query 66 | -- @param params 67 | -- 68 | -- @return mixed Value of the first column in the first row 69 | -- 70 | function MySQL.Sync.fetchScalar(query, params) 71 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 72 | 73 | local res = '' 74 | local finishedQuery = false 75 | exports['mysql-async']:mysql_fetch_scalar(query, safeParameters(params), function (result) 76 | res = result 77 | finishedQuery = true 78 | end) 79 | repeat Citizen.Wait(0) until finishedQuery == true 80 | return res 81 | end 82 | 83 | --- 84 | -- Execute a query and retrieve the last id insert, sync version 85 | -- 86 | -- @param query 87 | -- @param params 88 | -- 89 | -- @return mixed Value of the last insert id 90 | -- 91 | function MySQL.Sync.insert(query, params) 92 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 93 | 94 | local res = 0 95 | local finishedQuery = false 96 | exports['mysql-async']:mysql_insert(query, safeParameters(params), function (result) 97 | res = result 98 | finishedQuery = true 99 | end) 100 | repeat Citizen.Wait(0) until finishedQuery == true 101 | return res 102 | end 103 | 104 | --- 105 | -- Stores a query for later execution 106 | -- 107 | -- @param query 108 | -- 109 | function MySQL.Sync.store(query) 110 | assert(type(query) == "string", "The SQL Query must be a string") 111 | 112 | local res = -1 113 | local finishedQuery = false 114 | exports['mysql-async']:mysql_store(query, function (result) 115 | res = result 116 | finishedQuery = true 117 | end) 118 | repeat Citizen.Wait(0) until finishedQuery == true 119 | return res 120 | end 121 | 122 | --- 123 | -- Execute a List of querys and returns bool true when all are executed successfully 124 | -- 125 | -- @param querys 126 | -- @param params 127 | -- 128 | -- @return bool if the transaction was successful 129 | -- 130 | function MySQL.Sync.transaction(querys, params) 131 | local res = 0 132 | local finishedQuery = false 133 | exports['mysql-async']:mysql_transaction(querys, params, function (result) 134 | res = result 135 | finishedQuery = true 136 | end) 137 | repeat Citizen.Wait(0) until finishedQuery == true 138 | return res 139 | end 140 | 141 | --- 142 | -- Execute a query with no result required, async version 143 | -- 144 | -- @param query 145 | -- @param params 146 | -- @param func(int) 147 | -- 148 | function MySQL.Async.execute(query, params, func) 149 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 150 | 151 | exports['mysql-async']:mysql_execute(query, safeParameters(params), func) 152 | end 153 | 154 | --- 155 | -- Execute a query and fetch all results in an async way 156 | -- 157 | -- @param query 158 | -- @param params 159 | -- @param func(table) 160 | -- 161 | function MySQL.Async.fetchAll(query, params, func) 162 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 163 | 164 | exports['mysql-async']:mysql_fetch_all(query, safeParameters(params), func) 165 | end 166 | 167 | --- 168 | -- Execute a query and fetch the first column of the first row, async version 169 | -- Useful for count function by example 170 | -- 171 | -- @param query 172 | -- @param params 173 | -- @param func(mixed) 174 | -- 175 | function MySQL.Async.fetchScalar(query, params, func) 176 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 177 | 178 | exports['mysql-async']:mysql_fetch_scalar(query, safeParameters(params), func) 179 | end 180 | 181 | --- 182 | -- Execute a query and retrieve the last id insert, async version 183 | -- 184 | -- @param query 185 | -- @param params 186 | -- @param func(string) 187 | -- 188 | function MySQL.Async.insert(query, params, func) 189 | assert(type(query) == "string" or type(query) == "number", "The SQL Query must be a string") 190 | 191 | exports['mysql-async']:mysql_insert(query, safeParameters(params), func) 192 | end 193 | 194 | --- 195 | -- Stores a query for later execution 196 | -- 197 | -- @param query 198 | -- @param func(number) 199 | -- 200 | function MySQL.Async.store(query, func) 201 | assert(type(query) == "string", "The SQL Query must be a string") 202 | 203 | exports['mysql-async']:mysql_store(query, func) 204 | end 205 | 206 | --- 207 | -- Execute a List of querys and returns bool true when all are executed successfully 208 | -- 209 | -- @param querys 210 | -- @param params 211 | -- @param func(bool) 212 | -- 213 | function MySQL.Async.transaction(querys, params, func) 214 | return exports['mysql-async']:mysql_transaction(querys, params, func) 215 | end 216 | 217 | function MySQL.ready (callback) 218 | Citizen.CreateThread(function () 219 | -- add some more error handling 220 | while GetResourceState('mysql-async') ~= 'started' do 221 | Citizen.Wait(0) 222 | end 223 | while not exports['mysql-async']:is_ready() do 224 | Citizen.Wait(0) 225 | end 226 | callback() 227 | end) 228 | end 229 | -------------------------------------------------------------------------------- /src/ui/Nui.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 207 | 208 | 216 | -------------------------------------------------------------------------------- /src/docs/src/components/ConfigFXServer.vue: -------------------------------------------------------------------------------- 1 | 99 | 100 | 253 | --------------------------------------------------------------------------------