Skip to content

Instantly share code, notes, and snippets.

@MartinMajor
Created July 24, 2013 12:47
Show Gist options
  • Save MartinMajor/6070261 to your computer and use it in GitHub Desktop.
Save MartinMajor/6070261 to your computer and use it in GitHub Desktop.
Tools for database versioning. For more informations see: http://www.youtube.com/watch?v=KTmlw5AKM8E (in CZ). - database.sql script is written for PostgreSQL - DatabaseDeployPresenter.php script is a snippet from Nette presenter - post-checkout is Git hook, that calls shell script that just runs your Nette presenter
CREATE TABLE system.deployed_scripts
(
id serial NOT NULL,
filename character varying(255) NOT NULL,
inserted_datetime timestamp without time zone NOT NULL DEFAULT now(),
CONSTRAINT deployed_scripts_pkey PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
CREATE OR REPLACE FUNCTION system.deploy_script(in_filename character varying, in_dependence character varying[] DEFAULT NULL::character varying[])
RETURNS void AS
$BODY$
DECLARE
dependence RECORD;
BEGIN
IF (EXISTS(SELECT 1 FROM system.deployed_scripts WHERE lower(filename) = lower(in_filename))) THEN
RAISE EXCEPTION 'Script "%" is already deployed.', in_filename;
END IF;
IF (in_dependence IS NOT NULL) THEN
FOR dependence IN SELECT unnest(in_dependence) AS filename LOOP
IF (NOT EXISTS(SELECT 1 FROM system.deployed_scripts WHERE lower(filename) = lower(dependence.filename))) THEN
RAISE EXCEPTION 'Script "%" needs script "%" deployed.', in_filename, dependence.filename;
END IF;
END LOOP;
END IF;
INSERT INTO system.deployed_scripts(filename) VALUES(in_filename);
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE OR REPLACE FUNCTION system.list_deployed_scripts()
RETURNS SETOF character varying AS
$BODY$
BEGIN
RETURN QUERY SELECT filename AS filename FROM system.deployed_scripts;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
/**
* Startup
*/
public function startup()
{
parent::startup();
// plain text output when http request
$this->getHttpResponse()->setContentType('text/plain');
// error handler
$this->getApplication()->onError[] = function(\Nette\Application\Application $application, \Exception $exception) {
echo 'ERROR: ' . $exception->getMessage();
exit(1);
};
}
/**
* Lists all database scripts that need to be imported.
*/
public function actionListScriptsForDeploy()
{
$list = Fs::glob($this->getScriptsDir() . DIRECTORY_SEPARATOR . '*.sql', 0, TRUE);
$files = array();
foreach ($list as $file) {
$sqlFile = substr($file, strrpos($file, DIRECTORY_SEPARATOR) + 1);
$files[strtolower($sqlFile)] = realpath($file);
}
$deployedScripts = $this->connection->runFunction('system.list_deployed_scripts');
foreach ($deployedScripts as $script) {
$script = strtolower(reset($script));
if (isset($files[$script])) {
unset($files[$script]);
}
}
if ($files) {
echo "Please import these files into your database:\n";
foreach ($files as $file) {
echo "$file\n";
}
} else {
echo "Your database is up to date.\n";
}
$this->terminate();
}
/**
* Creates a new database script.
*/
public function actionCreateScript($name)
{
if (empty($name)) {
echo "You must specify script name.";
$this->terminate();
}
if (substr(strtolower($name), -4) == '.sql') {
$name = substr($name, 0, -4);
}
$date = date('Y-m-d');
$dir = $this->getScriptsDir() . DIRECTORY_SEPARATOR . date('Y', strtotime($date));
if (!file_exists($dir)) {
mkdir($dir, 0755, TRUE);
}
$dir = realpath($dir);
$filename = $date . '-' . $name . '.sql';
$file = $dir . DIRECTORY_SEPARATOR . $filename;
if (!file_exists($file)) {
file_put_contents($file, "-- ###### DEPLOY SCRIPT $filename ######\nSELECT system.deploy_script('$filename');\n\n\n-- ###### DEPLOY SCRIPT $filename ######\n\n");
echo "File '$file' was successfully created.\n";
} else {
echo "File '$file' already exists.\n";
}
$this->terminate();
}
#!/bin/sh
if [ -f ./tools/database-deploy/list-scripts.sh ]; then
cd tools/database-deploy
./list-scripts.sh
cd ../..
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment