## DB Migrate ## ========== ## ## Simple tool to manage database migrations. import json, times, os, docopt type DbMigrateConfig* = tuple[ driver, sqlDir, connectionString: string ] proc loadConfig*(filename: string): DbMigrateConfig = ## Load DbMigrateConfig from a file. let cfg = json.parseFile(filename) return ( driver: if cfg.hasKey("driver"): cfg["driver"].getStr else: "postres", sqlDir: if cfg.hasKey("sqlDir"): cfg["sqlDir"].getStr else: "migrations", connectionString: cfg["connectionString"].getStr) proc createMigration*(config: DBMigrateConfig, migrationName: string): seq[string] = ## Create a new set of database migration files. let timestamp = getTime().getLocalTime().format("yyyyMMddHHmmss") let filenamePrefix = timestamp & "-" & migrationName let upFilename = joinPath(config.sqlDir, filenamePrefix & "-up.sql") let downFilename = joinPath(config.sqlDir, filenamePrefix & "-down.sql") let scriptDesc = migrationName & " (" & timestamp & ")" let upFile = open(upFilename, fmWrite) let downFile = open(downFilename, fmWrite) upFile.writeLine "-- UP script for " & scriptDesc downFile.writeLine "-- DOWN script for " & scriptDesc upFile.close() downFile.close() return @[upFilename, downFilename] when isMainModule: let doc = """ Usage: db-migrate [options] create Options: -c --config Use the given configuration file (defaults to "database.json"). """ # Parse arguments let args = docopt(doc, version = "db-migrate 0.1.0") let exitErr = proc(msg: string): void = stderr.writeLine("db_migrate: " & msg) quit(QuitFailure) # Load configuration file let configFilename = if args["--config"]: $args["--config"] else: "database.json" var config: DbMigrateConfig try: config = loadConfig(configFilename) except IOError: exitErr "Cannot open config file: " & configFilename except: exitErr "Error parsing config file: " & configFilename & "\L\t" & getCurrentExceptionMsg() # Check for migrations directory if not existsDir config.sqlDir: try: echo "SQL directory '" & config.sqlDir & "' does not exist and will be created." createDir config.sqlDir except IOError: exitErr "Unable to create directory: " & config.sqlDir & ":\L\T" & getCurrentExceptionMsg() # Execute commands if args["create"]: try: let filesCreated = createMigration(config, $args[""]) echo "Created new migration files:" for filename in filesCreated: echo "\t" & filename except IOError: exitErr "Unable to create migration scripts: " & getCurrentExceptionMsg()