migration.anubis 7.16 KB
/*
 * Created by PyramIDE.
 * User: Steve Marechal
 * Date: 25/11/2008
 * Time: 11:29
 * 
 */

read tools/basis.anubis
read system/files.anubis
read system/logger.anubis
read system/string.anubis
read data_base/db_tools.anubis

read xlib/database/db_utils.anubis
read xlib/database/alter_table.anubis
//read xlib/net_services_protocols/logger_service.anubis

 read mf_constants.anubis

 read settings.anubis
read migration_common.anubis

 read tools/mf_loggers.anubis

define String dir_save_database = "/db_backup/".


/**
 * Compare two version string. Returns -1 if first is lower than second, 1 if first is greater than second, and 0 if equals.
 */
public define Int 
  compare_db_version
  (
    String version1,
    String version2
  ) =
  with compare = (List(String) v1, List(String) v2) |-compare-> (Int)
                  if v1 is
                  {
                    [] then 
                      if v2 is
                      {
                        [] then 0,
                        [h2 . t2] then -1
                      },
                    [h1 . t1] then
                      if v2 is
                      {
                        [] then 1,
                        [h2 . t2] then
                          if h1 = h2 then compare(t1, t2)
                          else
                            with v1i = force_Type(decimal_scan(h1), 0),
                                 v2i = force_Type(decimal_scan(h2), 0),
                            if v1i < v2i then -1
                            else if v1i > v2i then 1
                            else 0
                      },
                  },
  compare(split(version1, '.'), split(version2, '.')).

public define Maybe(One)
  backup_database
  (
    Logger        logger,
//    String        current_version,
    String        db_path,
    String        main_db_name,
    List(String)  other_db_names,
  )
  =
//  with should_copy = if file_exists(db_path + main_db_name) then
//                      if sqlite3_open(db_path + main_db_name) is
//                      {
//                        error(sql_error)        then false, // maybe not created yet
//                        ok(Database db)  then 
//                          with ver = get_version_settings(db),
//                          ver != current_version
//                      }
//                     else false,
                            
  //if should_copy then
    with  dir_save = db_path + dir_save_database, 
    if (Maybe(String))make_directory(dir_save) is
    {
      failure then logError(logger, "Can't create directory '"+db_path + dir_save_database+"'"); failure,
      success(_) then 
        with copy_with_log =  (String src, String dst) |-> 
                              if file_exists(src) then
                                if copy_file(src, dst) is
                                {
                                  cant_read_file          then logError(logger, "Can't read source file '" + src + "'."); failure,
                                  cant_create_file        then logError(logger, "Can't create destination file '" + dst + "'."); failure,
                                  copy_error              then logError(logger, "Can't copy file '" + src + "' to file '" + dst + "'."); failure,
                                  copy_file_mode_error    then logError(logger, "Can't get file mode for source file '" + src + "'."); failure,
                                  copy_file_times_error   then logError(logger, "Can't set file times into file '" + dst + "'."); failure,
                                  copy_ok(_)              then logInfo(logger, "File '" + dst + "' saved"); success(unique)
                                }
                              else success(unique),
        with copy_db = (List(String) names) |-copy_db->
                          if names is
                          {
                            [] then success(unique),
                            [h . t] then 
                              if copy_with_log(db_path + h, dir_save + h) is
                              {
                                failure then failure,
                                success(_) then copy_db(t)
                              }
                          },
        copy_db([main_db_name . other_db_names])
    }
  //else success(unique)
  .
    
  
  
  


public type Migration:
  migration(String version,
            (Database, Logger) -> Maybe(One)   migrate_to,
            (Database, Logger) -> Maybe(One)   create_tables,
            (Database, Logger) -> Maybe(One)   create_indexes,
           ).



define Maybe(One)  
  do_migration_loop
  (
    Database   db,
    Logger            logger,
    String            current_version,
    String            db_ver,
    List(Migration)   migrations,
    Maybe(Migration)  need_to_create_table,          // success in case of new DB or when no migration have been done
    (Database, String) -> One  update_db_version,
  ) =
  if migrations is
  {
    [] then 
      if need_to_create_table is
      {
        failure then
          update_db_version(db, current_version);
          success(unique),
        success(last) then
          if last is migration(_, _, create_tables, create_indexes) then
          if create_tables(db, logger) is success(_) then
            if create_indexes(db, logger) is success(_) then
              update_db_version(db, current_version);
              success(unique)
            else
              failure
          else
            failure
      },
    [h . t] then
      if h is migration(version, migrate_to, _, _) then
      if compare_db_version(db_ver, version) < 0 then
        logInfo(logger, "Migrating Database from version " + db_ver + " to version " + version);
        if migrate_to(db, logger) is failure then 
          failure
        else
          do_migration_loop(db, logger, current_version, version, t, failure, update_db_version)
      else 
        do_migration_loop(db, logger, current_version, db_ver, t, success(h), update_db_version),
  }.



public define Maybe(One)  
  do_migration
  (
    Database                    db,
    Logger                      logger,
    String                      current_version,
    (Database) -> String       get_db_version,
    (Database, String) -> One  update_db_version,
    List(Migration)             all_migrations,
  )=
  if is_empty_database(db) then  // new empty database
    logInfo(logger, "No database found. Creating a new one...");
    do_migration_loop(db, logger, current_version, "", [], last(all_migrations), update_db_version)
  else
  (
    with db_version = get_db_version(db),
    do_migration_loop(db, logger, current_version, db_version, all_migrations, failure, update_db_version)
  ).

public define Maybe(One)  
  do_create_indexes
  (
    Database         db,
    Logger                  logger,
    String                  current_version,
    List(Migration)         all_migrations,
  )=
  if last(all_migrations) is 
  {
    failure then logCriticalError(logger, "Index creation: migration list is empty!"); failure,
    success(last_migration) then
      if last_migration is migration(_, _, _, create_indexes) then
      if create_indexes(db, logger) is success(_) then
        success(unique)
      else
        failure
  }.