It is not a database/sql driver (read below for why this is impossible) but instead provides similar semantics, such as `Open()`, `Query()` and `QueryOne()`, `Next()`/`Scan()`/`Map()`, `Write()` and `WriteOne()`, etc.
* Abstracts the rqlite http API interaction - the POSTs, JSON handling, etc. You submit your SQL and get back an interator with familiar database/sql semantics (`Next()`, `Scan()`, etc.) or a `map[column name as string]interface{}.
* Timings and other metadata (e.g., num rows affected, last insert ID, etc.) is conveniently available and parsed into appropriate types.
* A connection abstraction allows gorqlite to discover and remember the rqlite leader. gorqlite will automatically try other peers if the leader is lost, enabling fault-tolerant API operations.
* Timeout can be set on a per-Connection basis to accomodate those with far-flung empires.
* Use familiar database URL connection strings to connection, optionally including rqlite authentication and/or specific rqlite consistency levels.
* Only a single node needs to be specified in the connection. gorqlite will talk to it and figure out the rest of the cluster from its redirects and status API.
If you use access control, any user connecting will need the "status" permission in addition to any other needed permission. This is so gorqlite can query the cluster and try other peers if the master is lost.
rqlite does not support iterative fetching from the DBMS, so your query will put all results into memory immediately. If you are working with large datasets on small systems, your experience may be suboptimal.
## TODO
https has not been tested yet. In theory, https should work just fine because it's just a URL to gorqlite, but it has not been.
Several features may be added in the future:
- support for the backup API
- support for expvars (debugvars)
- perhaps deleting a node (the remove API)
- since connections are just config info, it should be possible to clone them, which woud save startup time for new connections. This needs to be threadsafe, though, since a connection at any time could be updating its cluster info, etc.
- gorqlite always talks to the master (unless it's searching for a master). In theory, you talk to a non-master in "none" consistency mode, but this adds a surprising amount of complexity. gorqlite has to take note of the URL you call it with, then try to match that to the cluster's list to mark it as the "default" URL. Then whenever it wants to do an operation, it has to carefully sort the peer list based on the consistency model, if the defaut URL has gone away, etc. And when cluster info is rebuilt, it has to track the default URL through that.
## Why not a database/sql driver?
The original intent was to develop a proper database/sql driver, but this is not possible given rqlite's design. Also, this would limit the API to database/sql functions, and there were many more things we could do with rqlite (cluster status, etc.)
The chief reasons a proper database/sql driver is not possible are:
* rqlite supports transactions, but only in a single batch. You can group many statements into a single transaction, but you must submit them as a single unit. You cannot start a transaction, send some statements, come back later and submit some more, and then later commit.
* Prepared statements can be made and used using the `PreparedStatement` type. Create a new PreparedStatement instance with `NewPreparedStatement` with the SQL query as a string argument with sprintf syntax. Do not surround strings in quotes, as the `Bind` call will add those for you. See above for the usage.
* As a consequence, there is no point in having statements, so they are unsupported. At this point, so much of the `database/sql` API is returning `errors.New("NOT IMPLEMENTED")` that we might as well use an rqlite-specific library.
In `database/sql`, `Open()` doesn't actually do anything. You get a "connection" that doesn't connect until you `Ping()` or send actual work. In gorqlite's case, it needs to connect to get cluster information, so this is done immediately and automatically open calling `Open()`. By the time `Open()` is returned, gorqlite has full cluster info.
`Close()` will set a flag so if you try to use the connection afterwards, it will fail. But otherwise, you can merrily let your connections be garbage-collected with no harm, because they're just configuration tracking bundles and everything to the rqlite cluster is stateless. Indeed, the true reason that `Close()` exists is the author's feeling that if you open something, you should be able to close it. So why not `GetConnection()` then instead of `Open()`? Or `GetClusterConfigurationTrackingObject()`? I don't know. Fork me.
`Leader()` and `Peers()` will both cause gorqlite to reverify its cluster information before return. Note that if you call `Leader()` and then `Peers()` and something changes in between, it's possible to get inconsistent answers.
Since "weak" consistency is the default rqlite level, it is the default level for the client as well. The user can change this at will (either in the connection string or via `SetConsistencyLevel()`, and then the new level will apply to all future calls).
rqlite is supposed to be pronounced "ree qwell lite". So you could pronounce gorqlite as either "go ree kwell lite" or "gork lite". The Klingon in me prefers the latter. Really, isn't rqlite just the kind of battle-hardened, lean and mean system Klingons would use? **Qapla'!**