示例#1
0
    def test_delete_rows(self):

        # I could also just create the database and add rows but I feel like doing this
        tables = self._get_tables()
        rows = {
            'logs': ({
                'id': 2,
                'message': 'sup',
                'traceback': 'forever'
            }, )
        }

        database = database_reader(mysqldb(db_structure(tables, rows)))
        database.read_rows('logs')

        rows_from = {
            'logs': ({
                'id': 1,
                'message': 'hey',
                'traceback': 'never'
            }, {
                'id': 2,
                'message': 'sup',
                'traceback': 'forever'
            })
        }
        database_from = database_reader(
            mysqldb(db_structure(tables, rows_from)))
        database_from.read_rows('logs')

        operations = [
            str(op) for op in row_mygration(database, database_from).operations
        ]
        self.assertEquals(1, len(operations))
        self.assertEquals("DELETE FROM `logs` WHERE id=1;", operations[0])
示例#2
0
    def test_add_rows(self):

        # I could also just create the database and add rows but I feel like doing this
        tables = self._get_tables()
        rows = {
            'logs': ({
                'id': 1,
                'message': 'hey',
                'traceback': 'never'
            }, {
                'id': 2,
                'message': 'sup',
                'traceback': 'forever'
            })
        }

        database = database_reader(mysqldb(db_structure(tables, rows)))
        database.read_rows('logs')

        operations = [str(op) for op in row_mygration(database).operations]
        self.assertEquals(2, len(operations))
        self.assertEquals(
            "INSERT INTO `logs` (`id`, `message`, `traceback`) VALUES ('1', 'hey', 'never');",
            operations[0])
        self.assertEquals(
            "INSERT INTO `logs` (`id`, `message`, `traceback`) VALUES ('2', 'sup', 'forever');",
            operations[1])
示例#3
0
    def test_read_rows(self):

        tables = self._get_tables()
        rows = {
            'logs': ({
                'id': 1,
                'message': 'hey',
                'traceback': 'never'
            }, {
                'id': 2,
                'message': 'sup',
                'traceback': 'forever'
            })
        }

        database = database_reader(mysqldb(db_structure(tables, rows)))

        # quick double check
        self.assertTrue('logs' in database.tables)
        self.assertTrue('more_logs' in database.tables)

        database.read_rows('logs')

        self.assertTrue(database.tables['logs'].tracking_rows)
        rows = database.tables['logs'].rows
        self.assertEquals(1, rows[1]['id'])
        self.assertEquals('hey', rows[1]['message'])
        self.assertEquals('never', rows[1]['traceback'])

        self.assertEquals(2, rows[2]['id'])
        self.assertEquals('sup', rows[2]['message'])
        self.assertEquals('forever', rows[2]['traceback'])
示例#4
0
    def test_all(self):

        # I could also just create the database and add rows but I feel like doing this
        tables = self._get_tables()
        rows = {
            'logs': ({
                'id': 2,
                'message': 'sup',
                'traceback': 'whatever'
            }, {
                'id': 3,
                'message': 'okay',
                'traceback': 'always'
            })
        }

        database = database_reader(mysqldb(db_structure(tables, rows)))
        database.read_rows('logs')

        rows_from = {
            'logs': ({
                'id': 1,
                'message': 'hey',
                'traceback': 'never'
            }, {
                'id': 2,
                'message': 'sup',
                'traceback': 'forever'
            })
        }
        database_from = database_reader(
            mysqldb(db_structure(tables, rows_from)))
        database_from.read_rows('logs')

        operations = [
            str(op) for op in row_mygration(database, database_from).operations
        ]
        # don't be picky about the order
        self.assertEquals(3, len(operations))
        self.assertTrue(
            "INSERT INTO `logs` (`id`, `message`, `traceback`) VALUES ('3', 'okay', 'always');"
            in operations)
        self.assertTrue("DELETE FROM `logs` WHERE id=1;" in operations)
        self.assertTrue(
            "UPDATE `logs` SET `message`='sup', `traceback`='whatever' WHERE id=2;"
            in operations)
示例#5
0
    def build_commands(self):

        files_database = database_parser(self.config['files_directory'])

        # any errors or warnings?
        quit_early = False
        if files_database.errors and not self.options['force']:
            print('Errors found in *.sql files', file=sys.stderr)
            quit_early = True
            for error in files_database.errors:
                print(error, file=sys.stderr)

        # or 1215 errors?
        if files_database.errors_1215 and not self.options['force']:
            print('1215 errors encountered', sys.stderr)
            quit_early = True
            for error in files_database.errors_1215:
                print(error, file=sys.stderr)

        if quit_early:
            return []

        # use the credentials to load up a database connection
        live_database = database_reader(mysqldb(self.credentials))

        # we have to tell the live database to load records
        # for any tables we are tracking records for.
        # We use the "files" database as the "truth" because
        # just about any database can have records, but
        # that doesn't mean we want to track them.  We only
        # track them if the file has rows.
        for table in files_database.tables.values():
            if not table.tracking_rows:
                continue

            if not table.name in live_database.tables:
                continue

            live_database.read_rows(table)

        mygrate = mygration(files_database, live_database, False)

        ops = []
        if mygrate.operations:
            ops.extend(mygrate.operations)

        rows = row_mygration(files_database, live_database)
        if rows.operations:
            ops.extend(rows.operations)

        if not ops:
            return []

        return [
            disable_checks(),
            *ops,
            enable_checks(),
        ]
示例#6
0
    def test_simple(self):

        tables = self._get_tables()

        mock_db = db_structure(tables, {})
        database = database_reader(mysqldb(mock_db))

        # our parser should have a table!
        self.assertTrue('logs' in database.tables)
        self.assertTrue('more_logs' in database.tables)
    def test_modify_rows(self):
        """ Types can change depending on whether or not rows come out of files or the database.  As a result, equality comparison has to ignore type differences """

        # I could also just create the database and add rows but I feel like doing this
        tables = self._get_tables()
        rows = {
            'logs': ({
                'id': 1,
                'account_id': 1,
                'message': 'hey'
            }, {
                'id': 2,
                'account_id': 1,
                'message': 'sup'
            })
        }

        database = database_reader(mysqldb(db_structure(tables, rows)))
        database.read_rows('logs')

        rows_from = {
            'logs': ({
                'id': 1,
                'account_id': '1',
                'message': 'hey'
            }, {
                'id': 2,
                'account_id': '1',
                'message': 'sup'
            })
        }
        database_from = database_reader(
            mysqldb(db_structure(tables, rows_from)))
        database_from.read_rows('logs')

        operations = [
            str(op) for op in row_mygration(database, database_from).operations
        ]
        self.assertEquals(0, len(operations))
    def test_diff_with_null( self ):
        """ NULL should be allowed and should result in a MySQL NULL in the database

        The system was turning NULL into a literal 'NULL'.  Internally, NULL
        is handled as a None
        """
        tables = {
            'logs': """
                CREATE TABLE `logs` (
                    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
                    `message` TEXT NOT NULL,
                    `traceback` text,
                    PRIMARY KEY (`id`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"""
        }

        rows = {
            'logs': (
                { 'id': 1, 'message': 'from null to value', 'traceback': None },
                { 'id': 2, 'message': 'from value to null', 'traceback': 'forever' },
                { 'id': 3, 'message': 'from null to null', 'traceback': None },
            )
        }

        db_db = database_reader( mysqldb( db_structure( tables, rows ) ) )
        db_db.read_rows( 'logs' )

        # and one from a file
        table1 = """CREATE TABLE `logs` (
            `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
            `message` TEXT NOT NULL,
            `traceback` text,
            PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        INSERT INTO logs (id,message,traceback) VALUES (1,'from null to value', 'HEY');
        INSERT INTO logs (id,message,traceback) VALUES (2,'from value to null', NULL);
        INSERT INTO logs (id,message,traceback) VALUES (3,'from null to null', NULL);
        INSERT INTO logs (id,message,traceback) VALUES (4,'Insert Null',NULL);
        """
        files_db = file_reader( [ table1 ] )

        mygrate = row_mygration( files_db, db_db )
        ops = [ str( op ) for op in mygrate ]
        self.assertEquals( 3, len( ops ) )
        self.assertTrue( "INSERT INTO `logs` (`id`, `message`, `traceback`) VALUES ('4', 'Insert Null', NULL);" in ops )
        self.assertTrue( "UPDATE `logs` SET `message`='from null to value', `traceback`='HEY' WHERE id=1;" in ops )
        self.assertTrue( "UPDATE `logs` SET `message`='from value to null', `traceback`=NULL WHERE id=2;" in ops )
示例#9
0
    def test_diffs_with_quotes(self):
        """ Things that need backslashes can cause trouble """

        # stick close to our use case: get the comparison table from the "database"
        tables = {
            'logs':
            """
                CREATE TABLE `logs` (
                    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
                    `message` TEXT NOT NULL,
                    `traceback` text,
                    PRIMARY KEY (`id`)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"""
        }

        rows = {
            'logs': ({
                'id': 1,
                'message': 'test\\sup',
                'traceback': 'never'
            }, {
                'id': 2,
                'message': 'sup\\test',
                'traceback': 'forever'
            })
        }

        db_db = database_reader(mysqldb(db_structure(tables, rows)))
        db_db.read_rows('logs')

        # and one from a file
        table1 = """CREATE TABLE `logs` (
            `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
            `message` TEXT NOT NULL,
            `traceback` text,
            PRIMARY KEY (`id`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

        INSERT INTO logs (id,message,traceback) VALUES (1,'test\\sup', 'never');
        INSERT INTO logs (id,message,traceback) VALUES (2,'bob\\test', 'forever');
        """
        files_db = file_reader([table1])

        mygrate = row_mygration(files_db, db_db)
        ops = [str(op) for op in mygrate]
        self.assertEquals(1, len(ops))
        self.assertTrue("`message`='bob\\\\test'" in ops[0])
    def execute(self):

        files_database = database_parser(self.config['files_directory'])

        # use the credentials to load up a database connection
        live_database = database_reader(mysqldb(self.credentials))

        # we aren't outputting operations.  Instead we just need to know what tables
        # have changed (either structure or records).  The easiest (and slightly hack)
        # way to do that is to simply run an actual mygration and grab out the names
        # of the tables that have changed.  Cheating, I know
        self.modified_tables = {}
        mygrate = mygration(live_database, files_database, False)
        if mygrate.operations:
            for op in mygrate.operations:
                self.modified_tables[op.table_name] = True

        # we have to tell the live database to load records
        # for any tables we are tracking records for, according
        # to the files database.
        for table in files_database.tables.values():
            if not table.tracking_rows:
                continue
            if not table.name in live_database.tables:
                continue
            live_database.read_rows(table)

        rows = row_mygration(live_database, files_database)
        if rows.operations:
            for op in rows.operations:
                self.modified_tables[op.table_name] = True

        for table_name in self.modified_tables.keys():
            print('\033[1;33m\033[41m%s\033[0m' % table_name)
            table = live_database.tables[table_name]
            print(table.nice())

            if table.tracking_rows:
                print('\n')
                for row in table.rows.values():
                    print(row_insert(table.name, row))
示例#11
0
    def execute( self ):

        files_database = database_parser( self.config['files_directory'] )

        # any errors or warnings?
        if files_database.errors:
            print( 'Errors found in *.sql files' )
            for error in files_database.errors:
                print( error )

            return False

        # use the credentials to load up a database connection
        live_database = database_reader( mysqldb( self.credentials ) )

        # we have to tell the live database to load records
        # for any tables we are tracking records for.
        # We use the "files" database as the "truth" because
        # just about any database can have records, but
        # that doesn't mean we want to track them.  We only
        # track them if the file has rows.
        for table in files_database.tables.values():
            if not table.tracking_rows:
                continue

            if not table.name in live_database.tables:
                continue

            live_database.read_rows( table )

        mygrate = mygration( files_database, live_database )
        if mygrate.errors_1215:
            print( '1215 Errors encountered' )
            for error in mygrate.errors_1215:
                print( error )

        else:
            for op in mygrate.operations:
                live_database.apply_to_source( op )