This guide details how to create plugins for use db-patch with other databases, drivers or for create customized patches.
Currently only three databases are supported: MySQL, PostgreSQL and SQLite. However, the mechanism for support other databases is simple.
For connect to one database using ODBC only it is necessary define correclty the connection string. However, each database use its keywords for this purpose. Therefore, it is necessary associate each custom keyword with the keyword used by db-patch. The next table shows the default keywords used by db-patch for create an ODBC connection string.
Keyword | Meaning |
---|---|
USER | Database user |
PASSWORD | Database password |
SERVER | Hostname of database server |
PORT | Port of database server |
DRIVER | ODBC driver |
CHARSET | Database charset |
For instance, PostgreSQL uses the keyword UID instance of USER and PWD instance of PASSWORD. Therefore, it is necessary customize the connection string. To do this, it is necessary create a customized OdbcQueryBuilder and overwrite the method get_customized_keywords as it is shown in the next code listing.
import dbpatch.connection.odbc as odbc
from dbpatch.loader import Registry
class PostgreSQLQueryBuilder(odbc.OdbcQueryBuilder):
NAME = 'postgresql'
def get_internal_database(self):
return 'postgres'
def get_all_databases_query(self):
return "SELECT datname FROM pg_database WHERE datistemplate = false"
def get_customized_keywords(self):
return {'USER' : 'UID',
'PASSWORD' : 'PWD'}
def register(module_id):
Registry.register(module_id, PostgreSQLQueryBuilder)
The previous code listing shows other two methods that should be overwritten:
Other two aspects should be noted:
The NAME class attribute. Define the name that it will be used by db-patch for register the customized ODBC QueryBuilder.
Note
It is mandatory define the NAME attribute. The NAME is provided by the -E (–db-engine) command line option.
The register module method. Register the customized OdbcQueryBuilder for to be used by db-patch
Note
If the customized OdbcQueryBuilder is not registered, db-patch will not found it.
The method that creates the final ODBC connection string is OdbcQueryBuilder.get_connection_string. It is possible overwrite, but previously it is recommended to show the code of this method because it makes checks, and add optional options.
It is possible connect with the database engine using specific drivers instead of ODBC. For to do this, it is necessary provide a customized patcher.connection.Connection class and to use the –connection-plugins command line option.
For drivers compliant with the DB-API 2.0 specification the class patcher.connection.DbApi2Connection is provided. A new driver that use this class as parent class only should overwrite a few methods, define the NAME class attribute and register the connection (create a module method called register and use the method dbpatch.connection.ConnectionFactory.register_connection). Next, the methods to overwrite are enumerated.
Currently there are three native implementations that can be used as examples:
Note
For to use your new native connection it is necessary to provide the next command line options to db-patch
For create a new patch only it is necessary inherit of the class dbpatch.patch.Patch, provide an implementation of the execute method, add the EXTENSION class attribute, register the new patch (creating a module method called register and using the method dbpatch.patch.PatchFactory.register), and use the –patch-plugins command line option.
As example see the implementation of raw and sql patches (the code shown below correspond to used for manage raw patches).
import dbpatch.options
from dbpatch.log import LogFactory
import dbpatch.patch
from dbpatch.loader import Registry
class RawPatch(dbpatch.patch.Patch):
'''
Execute all the content of a file in a single query. Useful by
example for PL SQL scripts. Be careful, you must introduce
a single query.
The keyword 'mydb' will be replaced by each database name
'''
REGISTRY_ID = 'raw'
def __init__(self):
dbpatch.patch.Patch.__init__(self)
self._log = LogFactory().get_logger(RawPatch.__name__)
patch_file = self._options.get_option(dbpatch.options.PATCH_FILE)
self._queries = open(patch_file, 'r').read()
def execute(self, db_name):
connection = self.connect_to(db_name)
queries = self._queries.replace('mydb', db_name)
statement = self.create_statement(queries)
status = statement.execute()
if not status:
return False
return True
def register(module_id):
Registry.register(RawPatch)
Your new plugins could require more options. For this purpose you can use the –extra-opts command line option. This option recover a properties file and add them into the dbpatch.options.Options object. That is, for the next file
[myopt]
opt1 = first
opt2 = second
using the command line option
$> db-patch [...] --extra-opts myopt.cfg
your plugins can recover this properties from the Options object using the keywords myopt.opt1 and myopt.opt2 (section.option_name)
[...]
your_opt1 = Context().options.get_option('myopt.opt1')
your_opt2 = Context().options.get_option('myopt.opt2')
[...]