{"id":14972174,"url":"https://github.com/planetteamspeakk/mysqlw","last_synced_at":"2025-10-26T18:31:41.697Z","repository":{"id":44136800,"uuid":"329654350","full_name":"PlanetTeamSpeakk/MySQLw","owner":"PlanetTeamSpeakk","description":"A wrapper for MySQL connections for Java.","archived":false,"fork":false,"pushed_at":"2023-01-22T01:50:00.000Z","size":705,"stargazers_count":5,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-09-28T15:42:32.828Z","etag":null,"topics":["database","database-management","databases","gradle","java","mysql","mysql-connector","mysql-database","sqlite","sqlite3","wrapper"],"latest_commit_sha":null,"homepage":"https://mysqlw.ptsmods.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PlanetTeamSpeakk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-14T15:23:18.000Z","updated_at":"2024-02-25T20:12:16.000Z","dependencies_parsed_at":"2023-02-12T14:02:22.694Z","dependency_job_id":null,"html_url":"https://github.com/PlanetTeamSpeakk/MySQLw","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlanetTeamSpeakk%2FMySQLw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlanetTeamSpeakk%2FMySQLw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlanetTeamSpeakk%2FMySQLw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PlanetTeamSpeakk%2FMySQLw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PlanetTeamSpeakk","download_url":"https://codeload.github.com/PlanetTeamSpeakk/MySQLw/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219862312,"owners_count":16555956,"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":["database","database-management","databases","gradle","java","mysql","mysql-connector","mysql-database","sqlite","sqlite3","wrapper"],"created_at":"2024-09-24T13:46:29.930Z","updated_at":"2025-10-26T18:31:41.075Z","avatar_url":"https://github.com/PlanetTeamSpeakk.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MySQLw\n\n[![Latest release](https://img.shields.io/github/release/PlanetTeamSpeakk/MySQLw.svg)](https://github.com/PlanetTeamSpeakk/MySQLw/releases/latest)\n[![Build Status](https://api.travis-ci.org/PlanetTeamSpeakk/MySQLw.svg)](https://travis-ci.org/PlanetTeamSpeakk/MySQLw)\n[![Lines of code](https://img.shields.io/tokei/lines/github/PlanetTeamSpeakk/MySQLw?color=%23fe7d37)](#)\n### Link to [Javadoc](https://mysqlw.ptsmods.com)\n\nA wrapper for MySQL and SQLite connections for Java to make your life a lot easier and a lot saner when working with queries.  \nThis library is merely a wrapper for the default Java SQL library intended to be used with MySQL (or MariaDB for that matter) or SQLite, this means that you also need the MySQL Java connector or the SQLite Java connector to actually connect to your database, but the `Database#loadConnector(RDBMS, File, boolean)` method allows you to add it at runtime.\n\n* [Adding MySQLw to your project](#adding-mysqlw-to-your-project)\n  + [Gradle](#gradle)\n  + [Maven](#maven)\n* [Usage](#usage)\n  + [Connecting](#connecting)\n  + [Selecting](#selecting)\n  + [Inserting](#inserting)\n  + [Updating](#updating)\n  + [Replacing](#replacing)\n  + [Creating tables](#creating-tables)\n  + [Database-backed collections](#database-backed-collections)\n  + [Triggers and Procedures](#triggers-and-procedures)\n  + [Type conversion](#type-conversion)\n  + [Other smaller features](#other-smaller-features)\n* [Async](#async)\n\n## Adding MySQLw to your project\n### Gradle\nTo add MySQLw to your Gradle project, add the following line to your dependencies:\n```gradle\nimplementation 'com.ptsmods:mysqlw:1.9.2'\nimplementation 'com.ptsmods:mysqlw-collection:1.9.2' // For database-backed Java collections\nimplementation 'com.ptsmods:mysqlw-procedure:1.9.2' // For anything that has to do with procedures and triggers\n```\n\n### Maven\nTo add MySQLw to your Maven project, add the following code segment to your pom.xml file:\n```xml\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.ptsmods\u003c/groupId\u003e\n    \u003cartifactId\u003emysqlw\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.2\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.ptsmods\u003c/groupId\u003e\n    \u003cartifactId\u003emysqlw-collection\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.2\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.ptsmods\u003c/groupId\u003e\n    \u003cartifactId\u003emysqlw-procedure\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.2\u003c/version\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n## Usage\n### Connecting\n#### MySQL\nTo start off, you should connect to your database. Assuming the MySQL Java connector is on your classpath too, you can do so with the following code:\n```java\nString host = \"localhost\";\nint port = 3306;\nString name = \"mydatabase\";\nString username = \"root\";\nString password = null;\nDatabase db = Database.connect(host, port, name, username, password);\n```\n\n#### SQLite\nTo connect to an SQLite database, all you have to do is supply the location of the database file.  \nYou can do so like so:\n```java\nDatabase db = Database.connect(new File(\"sqlite.db\"));\n```\n\n### Loading the proper connector\nInstead of shadowing the connector library for the Relation Database Management System (RDBMS), you can download and load it with `Database#loadConnector(RDBMS, File, boolean)`.  \nFor instance, if you wish to download the MySQL connector and add it to the classpath, you can use\n```java\nDatabase.loadConnector(Database.RDBMS.MySQL, \"8.0.23\", new File(\"mysql-connector.jar\"), true);\n```\nThis will download the MySQL connector to `mysql-connector.jar` if it has not yet been downloaded to that location (if it has, it will ignore the downloading step as stated by the last parameter, the `useCache` boolean) and then add it to the classpath and verify that it worked.  \nIf you use this method and it did not successfully manage to load the connector, it will likely throw an `IOException`.  \nIt is not guaranteed that it will throw an exception on failure as an exception is only thrown while downloading, although without the connector, you'll get all kinds of other problems thrown anyway, so you'll find out nonetheless.\n\n### Selecting\nSelecting data is done easily. All data is parsed into a `SelectResults` object which is a list of `SelectResultsRow` which is a map of String keys and Object values.  \nSay you have the following table named people (credits to [TutorialRepublic](https://www.tutorialrepublic.com/php-tutorial/php-mysql-select-query.php)):\n```\n+----+------------+-----------+----------------------+\n| id | first_name | last_name | email                |\n+----+------------+-----------+----------------------+\n|  1 | Peter      | Parker    | peterparker@mail.com |\n|  2 | John       | Rambo     | johnrambo@mail.com   |\n|  3 | Clark      | Kent      | clarkkent@mail.com   |\n|  4 | John       | Carter    | johncarter@mail.com  |\n|  5 | Harry      | Potter    | harrypotter@mail.com |\n+----+------------+-----------+----------------------+\n```\nIf you wish to select the `last_name` column only you can do so with the following code segment:\n```java\nSelectResults results = db.select(\"people\", \"last_name\");\n```\nNow if you wish to do the same, but only if the id is greater than 3, you could use\n```java\nSelectResults results = db.select(\"people\", \"last_name\", QueryCondition.greater(\"id\", 3));\n```\nNow if you wish to only return results whose email address starts with 'john' and order by first_name and you also want the first_name column returned and only want at most two elements, you can do so with\n```java\nSelectResults results = db.select(\"people\", new String[] {\"first_name\", \"last_name\"}, QueryConditions.create(QueryCondition.greater(\"id\", 3)).and(QueryCondition.like(\"email\", \"john%\")), QueryOrder.by(\"first_name\"), QueryLimit.limit(2));\n```\nBesides just passing a String as the column, you can pass any CharSequence, more specifically the [QueryFunction](#queryfunction).\n\nIn conclusion, the select method is any of the following:\n```java\nDatabase.select(String table, CharSequence column);\nDatabase.select(String table, CharSequence column, QueryCondition condition);\nDatabase.select(String table, CharSequence column, QueryCondition condition, QueryOrder order, QueryLimit limit);\nDatabase.select(String table, CharSequence[] columns);\nDatabase.select(String table, CharSequence[] columns, QueryCondition condition);\nDatabase.select(String table, CharSequence[] columns, QueryCondition condition, QueryOrder order, QueryLimit limit);\n```\n\n#### SelectBuilder\nBecause using all those select methods can be quite tricky and messy, there's also a `SelectBuilder`.  \nAs well as making selecting cleaner, SelectBuilder allows you to pass an alias for certain columns, e.g. selecting `count(*)` as `count`, \nand you can select into tables and variables.  \n\nTo create a new SelectBuilder, either use `Database#selectBuilder(String)` or `SelectBuilder#create(Database, String)`.  \nTo select a column, use `SelectBuilder#select(CharSequence)`, `SelectBuilder#select(CharSequence, String)`, `SelectBuilder#select(CharSequence...)` or `SelectBuilder#select(Iterable)`. The second parameter of `SelectBuilder#select(CharSequence, String)` is an optional alias.  \nTo select into a table or variable, use `SelectBuilder#into(String)`.  \nTo supply a condition, use `SelectBuilder#where(QueryCondition)`.  \nTo supply an order, use `SelectBuilder#order(QueryOrder)`, `SelectBuilder#order(String)` or `SelectBuilder#order(String, QueryOrder.QueryDirection)`.  \nAnd last but not least, you can supply a limit using `SelectBuilder#limit(QueryLimit)`, `SelectBuilder#limit(int)` or `SelectBuilder#limit(int, int)`.  \n\nSay you have a list of CharSequences you'd like to select from a table named `users` and you'd like to descendingly sort them by when they were created, but you only want 10 people from the 6th page and you only want people whose first name is John and whose last name starts with a D and you also wish to store the result in a table named `tempusers` and would like to select the `created_at` column as `time`, then you could use this example:  \n```java\nDatabase db = ...;\nSelectResults res = db.selectBuilder(\"users\")\n    .select(columns)\n    .select(\"created_at\", \"time\")\n    .into(\"tempusers\")\n    .where(QueryCondition.equals(\"first_name\", \"John\").and(QueryCondition.like(\"last_name\", \"D%\")))\n    .order(\"time\", QueryOrder.OrderDirection.DESC)\n    .limit(10, 6 * 10)\n    .execute();\n```\n\n### Inserting\n#### New data\nInserting one value into one column is the easiest method. It can easily be done using\n```java\ndb.insert(\"people\", \"first_name\", \"Tony\");\n```\nInserting one row, but with multiple columns is nearly as easy. For that you could use\n```java\ndb.insert(\"people\", new String[] {\"first_name\", \"last_name\", \"email\"}, new Object[] {\"Tony\", \"Stark\", \"tonystark@mail.com\"});\n```\nYou can, however, also insert multiple rows at once. For this use\n```java\ndb.insert(\"people\", new String[] {\"first_name\", \"last_name\", \"email\"}, Lists.newArrayList(new Object[] {\"Tony\", \"Stark\", \"tonystark@mail.com\"}, new Object[] {\"Thor\", \"Odinson\", \"thorodison@mail.com\"}));\n```\nYou must also use this method if you wish to insert multiple values for one column, just wrap the name of that column in a String array.\n\n#### Update on duplicate\nYou also have the option to update columns of a row when a row with the same value for the PRIMARY KEY column already exists.\nSay for example you have a table like people and id is the PRIMARY KEY, you could then overwrite the data that already exists or insert new data if it does not, for example:\n```java\ndb.insertUpdate(\"people\", new String[] {\"id\", \"first_name\", \"last_name\", \"email\"}, new Object[] {3, \"Thor\", \"Odinson\", \"thorodinson@mail.com\"}, ImmutableMap.\u003cString, Object\u003ebuilder().put(\"email\", \"thorodinson@mail.com\").build());\n```\nThis would try to insert a new row with the values `3`, `Thor`, `Odinson` and `thorodinson@mail.com` for columns `id`, `first_name`, `last_name` and `email` into the table, but because there is already a row with the value 3 for the PRIMARY KEY column (id), it insteads updates the value of column `email` of that row to 'thorodinson@gmail.com'.\n\n#### Ignore on duplicate\nLast but not least, instead of updating on a duplicate PRIMARY KEY value, you can also choose to ignore the insertion.  \nAn example of this would be\n```java\ndb.insertIgnore(\"people\", new String[] {\"id\", \"first_name\", \"last_name\", \"email\"}, new Object[] {3, \"Thor\", \"Odinson\", \"thorodinson@mail.com\"}, \"id\");\n```\nWhere the last parameter 'id' is the name of the table's PRIMARY KEY column.  \nThis would end up doing nothing as there is already a row where column `id` has a value of 3.\n\n#### InsertBuilder\nAside from [SelectBuilder](#selectbuilder), there's also an InsertBuilder. This one is a little less sophisticated, however.  \nFor the time being, you can only do normal insertions and replacements with this class.  \nTo create an InsertBuilder, either use `Database#insertBuilder(String, String...)` or use `InsertBuilder#create(Database, String, String...)`.  \nThe String parameter here is the table to insert into and the String varargs are the columns to insert into.  \nTo insert data, use `InsertBuilder#insert(Object...)`, `InsertBuilder#insert(Object[]... values)` or `InsertBuilder#insert(Iterable)`.  \nThen use either `InsertBuilder#execute()` or `InsertBuilder#executeReplace()` to execute either an insert query or a replace query.  \n\n### Updating\nYou can also choose to update data rather than inserting it.  \nThis can be done rather easily using\n```java\ndb.update(\"people\", ImmutableMap.\u003cString, Object\u003ebuilder().put(\"email\", null).build(), QueryCondition.greater(\"id\", 4));\n```\nThis would set the `email` column to null for every row where `id` is greater than 4.\n\n### Replacing\nBesides inserting and updating, you can also replace rows.  \nThis is essentially the same as deleting any row with the same value for the PRIMARY KEY column and then inserting this one instead.  \nThe replace methods are the exact same as the insert methods as the queries look exactly the same, so for examples, have a look at inserting.\n\n### Creating tables\nCreating tables has not been made simpler, but it sure has been made more sane.  \nNow creating tables can be done using the following example:\n```java\nTablePreset.create(\"users\")\n    .putColumn(\"id\", ColumnType.BIGINT.struct()\n        .configure(sup -\u003e sup.apply(null))\n        .setPrimary(true)\n        .setNullAllowed(false))\n    .putColumn(\"username\", ColumnType.VARCHAR.struct()\n        .configure(sup -\u003e sup.apply(16))\n        .setNullAllowed(false))\n    .putColumn(\"password\", ColumnType.CHAR.struct()\n        .configure(sup -\u003e sup.apply(128))\n        .setNullAllowed(false))\n    .create(db);\n```\nThis preset would compile to `CREATE TABLE users (id BIGINT PRIMARY KEY NOT NULL, username VARCHAR(16) NOT NULL, password CHAR(128) NOT NULL);`.  \nAs you can see, it looks a little bit complicated at first sight, but it sure looks way prettier and leaves a lot less room for mistakes than just a plain `CREATE TABLE` query.  \n\nFor starters the `TablePreset#create(String)` method. This method creates a new TablePreset with the given name. This name can be changed later and if you plan on using the preset multiple times, it is recommended you do so using `preset.setName(\"newname\").create(db)`.  \n\nNext we have putting columns.  \nColumns are gotten by running `ColumnType#struct()` on your desired ColumnType.  \nIf the selected ColumnType has a supplier that requires parameters, **it is mandatory that you configure it**.  \nYou can do so using `ColumnStructure#configure(Function)` where the function takes a supplier of sorts and returns its value after passing it your desired values.  \nColumnTypes can have suppliers for various reasons, but most often it requires one value which is the length or maximum length of the type.  \nIn any case, any values passed to the supplier is what appears in the parentheses behind it.  \nSome, not all, suppliers also allow for being passed `null` values. Integers are an example of this.  \n\nLast we have any attributes the column might have, this could be anything and I suggest you read the javadoc on classes in the `com.ptsmods.mysqlw.table` class to find out more.\n\n### Database-backed collections\nNext we have the real cool feature, database-backed collections.  \nThese collections are just ordinary lists, sets or maps, but their values are never present on the VM, at least not in a significant way.  \nThese classes were written with concurrent modifications and efficiency in mind. Two instances connected to the same database could edit the same list, set or map at the same time and there would not be an issue.  \n\nAll DbCollection classes require functions to convert their elements or keys and values to and from Strings in order to be stored.  \nBasic functions for this and a registry for your own can be found in the DbCF (Database Collection Functions) class.\n\n#### DbList\nThis list works with a table with two columns in the background. One for an id and one for a value.  \nSince with lists the order matters and with MySQL auto-incrementing ids can be a bit unreliable (especially when adding a value somewhere in the list instead of at the end), whenever you remove a value or add one somewhere that's not at the end, the entire list is loaded, altered and inserted again.  \nThis can in some cases, especially with big lists, be problematic as it makes things slow, so keep that in mind.\n\n#### DbSet\nThis set is just like any other set, except its values are stored in a table.  \nThe table consists of one column, that being a TEXT type.  \nJust like your usual set, this set does not allow null or duplicate values and is more or less randomly ordered.\n\n#### DbMap\nA database-backed map, what else is there to say?  \nOh yeah, the table backing this map consists of two columns, one being the key with a type of VARCHAR(255), keep that maximum length in mind, the other being the value with a type of TEXT.  \n\n#### Creating database-backed collections\nGetting an instance of a DbList or a DbSet is more or less the same except for lists the method signature is `DbList#getList(Database, String, Class)` while for sets it's `DbSet#getSet(Database, String, Class)`, but you pass them the same parameters.  \nGetting a new list is thus done as follows:\n```java\nList\u003cString\u003e list = DbList.getList(db, \"testlist\", String.class);\n```\nIn this method, the parameters are in order: the database this list is on, the name of this list (used to determine the table name which is 'list_' + name) and the class of the type of this list.  \nThe last paremeter can be any class you like so long as it has type converters registered with `DbCF#registerConverters(Class, BiFunction, BiFunction)`.  \nBy default all basic Java types (String, Byte, Short, Integer, Long, Float and Double) are registered.  \nYou can, however, also nest DbLists, DbSets and DbMaps, to do so, you need to acquire their respective converters using the methods in the DbCF class.  \nThese methods are:\n  - `dbListToStringFunc()`\n  - `dbListFromStringFunc(Class)`\n  - `dbListFromStringFunc(BiFunction, BiFunction)`\n  - `dbSetToStringFunc()`\n  - `dbSetFromStringFunc(Class)`\n  - `dbSetFromStringFunc(BiFunction, BiFunction)`\n  - `dbMapToStringFunc()`\n  - `dbMapFromStringFunc(Class, Class)`\n  - `dbMapFromStringFunc(BiFunction, BiFunction, BiFunction, BiFunction)`  \nNote that the methods that require classes can only be used if those classes have registered type converters.  \n\nCreating a DbMap is nearly the same as creating a DbList or DbSet, except you pass two types or two pairs of type converters.  \nAn example would be:\n```\nMap\u003cString, Integer\u003e map = DbMap.getMap(db, \"testmap\", String.class, Integer.class);\n```\n\n### Triggers and Procedures\nSince 1.7, you can create triggers and procedures with MySQLw. These are created using the `BlockBuilder` class which has a method for every single statement supported by MySQLw and can be used to create most basic triggers and procedures. Any statement that's not supported can still be used with `BlockBuilder#raw(String)` or `RawStmt#raw(String)`, but if you rely on these, I suggest you [file an issue](https://github.com/PlanetTeamSpeakk/MySQLw/issues/new).  \nYou can create triggers using `Database#createTrigger(String, String, TriggeringEvent, BlockBuilder)` which creates a trigger with the given name on the given table.  \nProcedures can be created with `Database#createProcedure(String, ProcedureParameter[], BlockBuilder)` and called with `Database#call(String, Object...)`.  \nFor an example on how to use `BlockBuilder` to create blocks, have a look at [the test I made for it](https://github.com/PlanetTeamSpeakk/MySQLw/blob/main/src/test/java/com/ptsmods/mysqlw/test/MySQLTest.java#L207).  \n\nIt should also be noted that you can create your own statements if you wish, you'll just have to use `BlockBuilder#stmt(Statement)` to actually add it to BlockBuilders.  \nAny Statement implementing OpeningStatement will increase the indentation by one and any Statement implementing ClosingStatement will decrease it by one.\n\n### Type conversion\nBy default, MySQLw can use a null value, any type of Number, String or byte array (it is converted to hex String representation) in queries, but to do so, it must first prepare them.  \nThis preparation is known as type conversion. To register your own type converter so you can put for example entire lists into a column, use the `Database#registerTypeConverter(Class, Function)` method.\nAn example of a type converter would be:\n```java\nGson gson = new Gson();\nDatabase.registerTypeConverter(List.class, list -\u003e Database.enquote(gson.toJson(list)), s -\u003e gson.fromJson(s, List.class));\n```\nThis would allow you to use lists when inserting data by turning the list into a JSON representation of it and enquoting it.  \nUsing this newly added type converter is as simple as just passing it as a value when inserting, e.g.:\n```java\ndb.insert(\"data\", \"value\", Lists.newArrayList(\"This is a JSON list\", \"with numerous values\", \"How neat!\"));\n```\nWhich would put the string `'[\"This is a JSON list\", \"with numerous values\", \"How neat!\"]'` into the query.  \nDo not forget that enquoting is mandatory whenever you insert anything as a literal String into a table, not doing so will end up in SQLExceptions.\n\n### Other smaller features\n#### Counting\nTo count the amount of columns in a table, you can use the `Database#count(String, String, QueryCondition)` method.  \nThis is basically a select query, except it only returns the requested value of count.  \nTo use this, you could try the following code:\n```java\nint count = db.count(\"people\", \"*\", QueryCondition.like(\"email\", \"john%\"));\n```\nThis will return the amount of rows in the table `people` where the email starts with 'john'.\nIn case of the previous table, this would be 2.\n\n#### Truncate\nTo completely wipe a table (truncating), you can use\n```java\ndb.truncate(\"people\");\n```\nThis will clear the whole table and also reset the starting value of the id column assuming it has the AUTO_INCREMENT attribute so any new entries will start at 1.\n\n#### Delete\nDeleting data is also made easy as that is the entire purpose of this library. It can be done using the following code:\n```java\nint affected = db.delete(\"people\", QueryCondtions.create(QueryCondition.equals(\"first_name\", \"Harry\")).or(QueryCondition.equals(\"first_name\", \"Clark\")));\n```\nThis would remove Harry Potter and Clark Kent from the table and return 2 as that is the amount of rows it affected.\n\n#### QueryFunction\nThis class is used to put a raw String into a query. This is especially useful when you want to check against JSON columns or any other context where you may want to use any sort of function (count is also an example).  \nTo use a `QueryFunction` in a select query, you could use the following:\n```java\nSelectResults results = db.select(\"people\", new QueryFunction(\"count(*)\"), null, null);\n```\nThis would return a `SelectResults` object with its only value being the result of the count function. (Although in this case, you could also use the `Database#count(String, String, QueryCondition)` method.)\n\n#### Enquoting\nEnquoting is as simple as putting a String in between single quotes and escaping all single quotes it contains by replacing them with two single quotes.  \nEnquoting can be done using\n```java\nString s = Database.enquote(\"Test'S'tring\");\n```\nThis would return `'Test''S''tring` which can safely be used to insert directly into a query.  \nIf you wish to just escape quotes and don't put the string in two single quotes in a whole, you can use\n```java\nString s = Database.escapeQuotes(\"Test'S'tring\");\n```\nThis would return `Test''S''tring` which is the same value as with enquoting, except not put in quotes.\n\n#### Dropping\nTo completely delete a table (dropping), you can use the following code:\n```java\ndb.drop(\"people\");\n```\n\n## Async\nNearly every method that uses the database connection in one way or another has an async version that uses `CompletableFuture`s to run the method asynchronously.  \nFor example, to insert data asynchronously, you can do the following:\n```java\ndb.selectAsync(\"people\", \"*\").thenAccept(results -\u003e {\n\t// Do something with the results.\n});\n```\nThis will prevent blocking the main thread or whatever thread you wish to run it on.  \nBy default, these `CompletableFuture`s use an executor that suits the RDBMS type. This is a normal cached threadpool for MySQL (see `Executors#newCachedThreadPool(ThreadFactory)`) and a fixed-size threadpool that only allows one thread for SQLite. The latter is to prevent blocking.  \nThis executor can be gotten using `Database#getExecutor()` and set using `Database#setExecutor(executor)`.  \nWith asynchronous calls always comes the struggle of correctly catching exceptions, for this reason you can set your own errorhandler using `Database#setErrorHandler(Consumer)`, this consumer will then be called whenever an error was thrown during any asynchronous database call.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplanetteamspeakk%2Fmysqlw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplanetteamspeakk%2Fmysqlw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplanetteamspeakk%2Fmysqlw/lists"}