Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
__init__.py978 linesDownload Raw Back to schema_diff
1##########################################################################2#3# pgAdmin 4 - PostgreSQL Tools4#5# Copyright (C) 2013 - 2024, The pgAdmin Development Team6# This software is released under the PostgreSQL Licence7#8##########################################################################9 10"""A blueprint module implementing the schema_diff frame."""11import json12import pickle13import secrets14import copy15 16from flask import Response, session, url_for, request17from flask import render_template, current_app as app18from flask_security import current_user19from pgadmin.user_login_check import pga_login_required20from flask_babel import gettext21from pgadmin.utils import PgAdminModule22from pgadmin.utils.ajax import make_json_response, bad_request, \23    make_response as ajax_response, internal_server_error24from pgadmin.model import Server, SharedServer25from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry26from pgadmin.tools.schema_diff.model import SchemaDiffModel27from config import PG_DEFAULT_DRIVER28from pgadmin.utils.driver import get_driver29from pgadmin.utils.constants import PREF_LABEL_DISPLAY, MIMETYPE_APP_JS,\30    ERROR_MSG_TRANS_ID_NOT_FOUND31from sqlalchemy import or_32from pgadmin.authenticate import socket_login_required33from pgadmin import socketio34 35MODULE_NAME = 'schema_diff'36COMPARE_MSG = gettext("Comparing objects...")37SOCKETIO_NAMESPACE = '/{0}'.format(MODULE_NAME)38 39 40class SchemaDiffModule(PgAdminModule):41    """42    class SchemaDiffModule(PgAdminModule)43 44        A module class for Schema Diff derived from PgAdminModule.45    """46 47    LABEL = gettext("Schema Diff")48 49    def get_own_menuitems(self):50        return {}51 52    def get_exposed_url_endpoints(self):53        """54        Returns:55            list: URL endpoints for Schema Diff module56        """57        return [58            'schema_diff.initialize',59            'schema_diff.panel',60            'schema_diff.servers',61            'schema_diff.databases',62            'schema_diff.schemas',63            'schema_diff.ddl_compare',64            'schema_diff.connect_server',65            'schema_diff.connect_database',66            'schema_diff.get_server',67            'schema_diff.close'68        ]69 70    def register_preferences(self):71 72        self.preference.register(73            'display', 'ignore_whitespaces',74            gettext("Ignore Whitespace"), 'boolean', False,75            category_label=PREF_LABEL_DISPLAY,76            help_str=gettext('Set ignore whitespace on or off by default in '77                             'the drop-down menu near the Compare button in '78                             'the Schema Diff tab.')79        )80 81        self.preference.register(82            'display', 'ignore_owner',83            gettext("Ignore Owner"), 'boolean', False,84            category_label=PREF_LABEL_DISPLAY,85            help_str=gettext('Set ignore owner on or off by default in the '86                             'drop-down menu near the Compare button in the '87                             'Schema Diff tab.')88        )89 90        self.preference.register(91            'display', 'ignore_tablespace',92            gettext("Ignore Tablespace"), 'boolean', False,93            category_label=PREF_LABEL_DISPLAY,94            help_str=gettext('Set ignore tablespace on or off by default in '95                             'the drop-down menu near the Compare button in '96                             'the Schema Diff tab.')97        )98 99        self.preference.register(100            'display', 'ignore_grants',101            gettext("Ignore Grants/Revoke"), 'boolean', False,102            category_label=PREF_LABEL_DISPLAY,103            help_str=gettext('Set ignore grants/revoke on or off by default '104                             'in the drop-down menu near the Compare button '105                             'in the Schema Diff tab.')106        )107 108 109blueprint = SchemaDiffModule(MODULE_NAME, __name__, static_url_path='/static')110 111 112@blueprint.route("/")113@pga_login_required114def index():115    return bad_request(116        errormsg=gettext('This URL cannot be requested directly.')117    )118 119 120@blueprint.route(121    '/panel/<int:trans_id>/<path:editor_title>',122    methods=["GET"],123    endpoint='panel'124)125def panel(trans_id, editor_title):126    """127    This method calls index.html to render the schema diff.128 129    Args:130        editor_title: Title of the editor131    """132    # If title has slash(es) in it then replace it133    if request.args and request.args['fslashes'] != '':134        try:135            fslashes_list = request.args['fslashes'].split(',')136            for idx in fslashes_list:137                idx = int(idx)138                editor_title = editor_title[:idx] + '/' + editor_title[idx:]139        except IndexError as e:140            app.logger.exception(e)141 142    return render_template(143        "schema_diff/index.html",144        _=gettext,145        trans_id=trans_id,146        editor_title=editor_title,147    )148 149 150def check_transaction_status(trans_id):151    """152    This function is used to check the transaction id153    is available in the session object.154 155    Args:156        trans_id:157    """158 159    if 'schemaDiff' not in session:160        return False, ERROR_MSG_TRANS_ID_NOT_FOUND, None, None161 162    schema_diff_data = session['schemaDiff']163 164    # Return from the function if transaction id not found165    if str(trans_id) not in schema_diff_data:166        return False, ERROR_MSG_TRANS_ID_NOT_FOUND, None, None167 168    # Fetch the object for the specified transaction id.169    # Use pickle.loads function to get the model object170    session_obj = schema_diff_data[str(trans_id)]171    diff_model_obj = pickle.loads(session_obj['diff_model_obj'])172 173    return True, None, diff_model_obj, session_obj174 175 176def update_session_diff_transaction(trans_id, session_obj, diff_model_obj):177    """178    This function is used to update the diff model into the session.179    :param trans_id:180    :param session_obj:181    :param diff_model_obj:182    :return:183    """184    session_obj['diff_model_obj'] = pickle.dumps(diff_model_obj, -1)185 186    if 'schemaDiff' in session:187        schema_diff_data = session['schemaDiff']188        schema_diff_data[str(trans_id)] = session_obj189        session['schemaDiff'] = schema_diff_data190 191 192@blueprint.route(193    '/initialize',194    methods=["GET"],195    endpoint="initialize"196)197@pga_login_required198def initialize():199    """200    This function will initialize the schema diff and return the list201    of all the server's.202    """203    trans_id = None204    try:205        # Create a unique id for the transaction206        trans_id = str(secrets.choice(range(1, 9999999)))207 208        if 'schemaDiff' not in session:209            schema_diff_data = dict()210        else:211            schema_diff_data = session['schemaDiff']212 213        # Use pickle to store the Schema Diff Model which will be used214        # later by the diff module.215        schema_diff_data[trans_id] = {216            'diff_model_obj': pickle.dumps(SchemaDiffModel(), -1)217        }218 219        # Store the schema diff dictionary into the session variable220        session['schemaDiff'] = schema_diff_data221 222    except Exception as e:223        app.logger.exception(e)224 225    return make_json_response(226        data={'schemaDiffTransId': trans_id})227 228 229@blueprint.route('/close/<int:trans_id>',230                 methods=["DELETE"],231                 endpoint='close')232def close(trans_id):233    """234    Remove the session details for the particular transaction id.235 236    Args:237        trans_id: unique transaction id238    """239    if 'schemaDiff' not in session:240        return make_json_response(data={'status': True})241 242    schema_diff_data = session['schemaDiff']243 244    # Return from the function if transaction id not found245    if str(trans_id) not in schema_diff_data:246        return make_json_response(data={'status': True})247 248    try:249        # Remove the information of unique transaction id from the250        # session variable.251        schema_diff_data.pop(str(trans_id), None)252        session['schemaDiff'] = schema_diff_data253    except Exception as e:254        app.logger.error(e)255        return internal_server_error(errormsg=str(e))256 257    return make_json_response(data={'status': True})258 259 260@blueprint.route(261    '/servers',262    methods=["GET"],263    endpoint="servers"264)265@pga_login_required266def servers():267    """268    This function will return the list of servers for the specified269    server id.270    """271    res = {}272    auto_detected_server = None273    try:274        """Return a JSON document listing the server groups for the user"""275        driver = get_driver(PG_DEFAULT_DRIVER)276 277        from pgadmin.browser.server_groups.servers import\278            server_icon_and_background279 280        for server in Server.query.filter(281                or_(Server.user_id == current_user.id, Server.shared)):282 283            shared_server = SharedServer.query.filter_by(284                name=server.name, user_id=current_user.id,285                servergroup_id=server.servergroup_id).first()286 287            if server.discovery_id:288                auto_detected_server = server.name289 290            if shared_server and shared_server.name == auto_detected_server:291                continue292 293            manager = driver.connection_manager(server.id)294            conn = manager.connection()295            connected = conn.connected()296            server_info = {297                "value": server.id,298                "label": server.name,299                "image": server_icon_and_background(connected, manager,300                                                    server),301                "_id": server.id,302                "connected": connected303            }304 305            if server.servers.name in res:306                res[server.servers.name].append(server_info)307            else:308                res[server.servers.name] = [server_info]309 310    except Exception as e:311        app.logger.exception(e)312 313    return make_json_response(data=res)314 315 316@blueprint.route(317    '/get_server/<int:sid>/<int:did>',318    methods=["GET"],319    endpoint="get_server"320)321@pga_login_required322def get_server(sid, did):323    """324    This function will return the server details for the specified325    server id.326    """327    res = []328    try:329        """Return a JSON document listing the server groups for the user"""330        driver = get_driver(PG_DEFAULT_DRIVER)331 332        server = Server.query.filter_by(id=sid).first()333        manager = driver.connection_manager(sid)334        conn = manager.connection(did=did)335        connected = conn.connected()336 337        res = {338            "sid": sid,339            "name": server.name,340            "user": server.username,341            "gid": server.servergroup_id,342            "type": manager.server_type,343            "connected": connected,344            "database": conn.db345        }346 347    except Exception as e:348        app.logger.exception(e)349 350    return make_json_response(data=res)351 352 353@blueprint.route(354    '/server/connect/<int:sid>',355    methods=["POST"],356    endpoint="connect_server"357)358@pga_login_required359def connect_server(sid):360    # Check if server is already connected then no need to reconnect again.361    driver = get_driver(PG_DEFAULT_DRIVER)362    manager = driver.connection_manager(sid)363    conn = manager.connection()364    if conn.connected():365        return make_json_response(366            success=1,367            info=gettext("Server connected."),368            data={}369        )370 371    server = Server.query.filter_by(id=sid).first()372    view = SchemaDiffRegistry.get_node_view('server')373    return view.connect(server.servergroup_id, sid)374 375 376@blueprint.route(377    '/database/connect/<int:sid>/<int:did>',378    methods=["POST"],379    endpoint="connect_database"380)381@pga_login_required382def connect_database(sid, did):383    server = Server.query.filter_by(id=sid).first()384    view = SchemaDiffRegistry.get_node_view('database')385    return view.connect(server.servergroup_id, sid, did)386 387 388@blueprint.route(389    '/databases/<int:sid>',390    methods=["GET"],391    endpoint="databases"392)393@pga_login_required394def databases(sid):395    """396    This function will return the list of databases for the specified397    server id.398    """399    res = []400    try:401        view = SchemaDiffRegistry.get_node_view('database')402 403        server = Server.query.filter_by(id=sid).first()404        response = view.nodes(gid=server.servergroup_id, sid=sid,405                              is_schema_diff=True)406        databases = json.loads(response.data)['data']407        for db in databases:408            res.append({409                "value": db['_id'],410                "label": db['label'],411                "_id": db['_id'],412                "connected": db['connected'],413                "allowConn": db['allowConn'],414                "image": db['icon'],415                "canDisconn": db['canDisconn'],416                "is_maintenance_db": db['label'] == server.maintenance_db417            })418 419    except Exception as e:420        app.logger.exception(e)421 422    return make_json_response(data=res)423 424 425@blueprint.route(426    '/schemas/<int:sid>/<int:did>',427    methods=["GET"],428    endpoint="schemas"429)430@pga_login_required431def schemas(sid, did):432    """433    This function will return the list of schemas for the specified434    server id and database id.435    """436    res = []437    try:438        schemas = get_schemas(sid, did)439        if schemas is not None:440            for sch in schemas:441                res.append({442                    "value": sch['_id'],443                    "label": sch['label'],444                    "_id": sch['_id'],445                    "image": sch['icon'],446                })447    except Exception as e:448        app.logger.exception(e)449 450    return make_json_response(data=res)451 452 453@socketio.on('compare_database', namespace=SOCKETIO_NAMESPACE)454@socket_login_required455def compare_database(params):456    """457    This function will compare the two databases.458    """459    # Check the pre validation before compare460    status, error_msg, diff_model_obj, session_obj = \461        compare_pre_validation(params['trans_id'], params['source_sid'],462                               params['target_sid'])463    if not status:464        socketio.emit('compare_database_failed',465                      error_msg.json if isinstance(466                          error_msg, Response) else error_msg,467                      namespace=SOCKETIO_NAMESPACE, to=request.sid)468        return error_msg469 470    comparison_result = []471 472    socketio.emit('compare_status', {'diff_percentage': 0,473                  'compare_msg': COMPARE_MSG}, namespace=SOCKETIO_NAMESPACE,474                  to=request.sid)475    update_session_diff_transaction(params['trans_id'], session_obj,476                                    diff_model_obj)477 478    try:479        ignore_owner = bool(params['ignore_owner'])480        ignore_whitespaces = bool(params['ignore_whitespaces'])481        ignore_tablespace = bool(params['ignore_tablespace'])482        ignore_grants = bool(params['ignore_grants'])483 484        # Fetch all the schemas of source and target database485        # Compare them and get the status.486        schema_result = \487            fetch_compare_schemas(params['source_sid'], params['source_did'],488                                  params['target_sid'], params['target_did'])489 490        total_schema = len(schema_result['source_only']) + len(491            schema_result['target_only']) + len(492            schema_result['in_both_database'])493 494        node_percent = 0495        if total_schema > 0:496            node_percent = round(100 / (total_schema * len(497                SchemaDiffRegistry.get_registered_nodes())), 2)498        total_percent = 0499 500        # Compare Database objects501        comparison_schema_result, total_percent = \502            compare_database_objects(503                trans_id=params['trans_id'], session_obj=session_obj,504                source_sid=params['source_sid'],505                source_did=params['source_did'],506                target_sid=params['target_sid'],507                target_did=params['target_did'],508                diff_model_obj=diff_model_obj, total_percent=total_percent,509                node_percent=node_percent, ignore_owner=ignore_owner,510                ignore_whitespaces=ignore_whitespaces,511                ignore_tablespace=ignore_tablespace,512                ignore_grants=ignore_grants)513        comparison_result = \514            comparison_result + comparison_schema_result515 516        # Compare Schema objects517        if 'source_only' in schema_result and \518                len(schema_result['source_only']) > 0:519            for item in schema_result['source_only']:520                comparison_schema_result, total_percent = \521                    compare_schema_objects(522                        trans_id=params['trans_id'], session_obj=session_obj,523                        source_sid=params['source_sid'],524                        source_did=params['source_did'],525                        source_scid=item['scid'],526                        target_sid=params['target_sid'],527                        target_did=params['target_did'], target_scid=None,528                        schema_name=item['schema_name'],529                        diff_model_obj=diff_model_obj,530                        total_percent=total_percent,531                        node_percent=node_percent,532                        is_schema_source_only=True,533                        ignore_owner=ignore_owner,534                        ignore_whitespaces=ignore_whitespaces,535                        ignore_tablespace=ignore_tablespace,536                        ignore_grants=ignore_grants)537 538                comparison_result = \539                    comparison_result + comparison_schema_result540 541        if 'target_only' in schema_result and \542                len(schema_result['target_only']) > 0:543            for item in schema_result['target_only']:544                comparison_schema_result, total_percent = \545                    compare_schema_objects(546                        trans_id=params['trans_id'], session_obj=session_obj,547                        source_sid=params['source_sid'],548                        source_did=params['source_did'],549                        source_scid=None, target_sid=params['target_sid'],550                        target_did=params['target_did'],551                        target_scid=item['scid'],552                        schema_name=item['schema_name'],553                        diff_model_obj=diff_model_obj,554                        total_percent=total_percent,555                        node_percent=node_percent,556                        ignore_owner=ignore_owner,557                        ignore_whitespaces=ignore_whitespaces,558                        ignore_tablespace=ignore_tablespace,559                        ignore_grants=ignore_grants)560 561                comparison_result = \562                    comparison_result + comparison_schema_result563 564        # Compare the two schema present in both the databases565        if 'in_both_database' in schema_result and \566                len(schema_result['in_both_database']) > 0:567            for item in schema_result['in_both_database']:568                comparison_schema_result, total_percent = \569                    compare_schema_objects(570                        trans_id=params['trans_id'], session_obj=session_obj,571                        source_sid=params['source_sid'],572                        source_did=params['source_did'],573                        source_scid=item['src_scid'],574                        target_sid=params['target_sid'],575                        target_did=params['target_did'],576                        target_scid=item['tar_scid'],577                        schema_name=item['schema_name'],578                        diff_model_obj=diff_model_obj,579                        total_percent=total_percent,580                        node_percent=node_percent,581                        ignore_owner=ignore_owner,582                        ignore_whitespaces=ignore_whitespaces,583                        ignore_tablespace=ignore_tablespace,584                        ignore_grants=ignore_grants)585 586                comparison_result = \587                    comparison_result + comparison_schema_result588 589        # Update the message and total percentage done in session object590        update_session_diff_transaction(params['trans_id'], session_obj,591                                        diff_model_obj)592 593    except Exception as e:594        app.logger.exception(e)595        socketio.emit('compare_database_failed', str(e),596                      namespace=SOCKETIO_NAMESPACE, to=request.sid)597 598    socketio.emit('compare_database_success', comparison_result,599                  namespace=SOCKETIO_NAMESPACE, to=request.sid)600 601 602@socketio.on('compare_schema', namespace=SOCKETIO_NAMESPACE)603@socket_login_required604def compare_schema(params):605    """606    This function will compare the two schema.607    """608    # Check the pre validation before compare609    status, error_msg, diff_model_obj, session_obj = \610        compare_pre_validation(params['trans_id'], params['source_sid'],611                               params['target_sid'])612    if not status:613        socketio.emit('compare_schema_failed',614                      error_msg.json if isinstance(615                          error_msg, Response) else error_msg,616                      namespace=SOCKETIO_NAMESPACE, to=request.sid)617        return error_msg618 619    comparison_result = []620 621    update_session_diff_transaction(params['trans_id'], session_obj,622                                    diff_model_obj)623    try:624        ignore_owner = bool(params['ignore_owner'])625        ignore_whitespaces = bool(params['ignore_whitespaces'])626        ignore_tablespace = bool(params['ignore_tablespace'])627        ignore_grants = bool(params['ignore_grants'])628        all_registered_nodes = SchemaDiffRegistry.get_registered_nodes()629        node_percent = round(100 / len(all_registered_nodes), 2)630        total_percent = 0631 632        comparison_schema_result, total_percent = \633            compare_schema_objects(634                trans_id=params['trans_id'], session_obj=session_obj,635                source_sid=params['source_sid'],636                source_did=params['source_did'],637                source_scid=params['source_scid'],638                target_sid=params['target_sid'],639                target_did=params['target_did'],640                target_scid=params['target_scid'],641                schema_name=gettext('Schema Objects'),642                diff_model_obj=diff_model_obj,643                total_percent=total_percent,644                node_percent=node_percent,645                ignore_owner=ignore_owner,646                ignore_whitespaces=ignore_whitespaces,647                ignore_tablespace=ignore_tablespace,648                ignore_grants=ignore_grants)649 650        comparison_result = \651            comparison_result + comparison_schema_result652 653        # Update the message and total percentage done in session object654        update_session_diff_transaction(params['trans_id'], session_obj,655                                        diff_model_obj)656 657    except Exception as e:658        app.logger.exception(e)659        socketio.emit('compare_schema_failed', str(e),660                      namespace=SOCKETIO_NAMESPACE, to=request.sid)661    socketio.emit('compare_schema_success', comparison_result,662                  namespace=SOCKETIO_NAMESPACE, to=request.sid)663 664 665@blueprint.route(666    '/ddl_compare/<int:trans_id>/<int:source_sid>/<int:source_did>/'667    '<int:source_scid>/<int:target_sid>/<int:target_did>/<int:target_scid>/'668    '<int:source_oid>/<int:target_oid>/<node_type>/<comp_status>/',669    methods=["GET"],670    endpoint="ddl_compare"671)672@pga_login_required673def ddl_compare(trans_id, source_sid, source_did, source_scid,674                target_sid, target_did, target_scid, source_oid,675                target_oid, node_type, comp_status):676    """677    This function is used to compare the specified object and return the678    DDL comparison.679    """680    # Check the transaction and connection status681    _, error_msg, _, _ = \682        check_transaction_status(trans_id)683 684    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:685        return make_json_response(success=0, errormsg=error_msg, status=404)686 687    view = SchemaDiffRegistry.get_node_view(node_type)688    if view and hasattr(view, 'ddl_compare'):689        sql = view.ddl_compare(source_sid=source_sid, source_did=source_did,690                               source_scid=source_scid, target_sid=target_sid,691                               target_did=target_did, target_scid=target_scid,692                               source_oid=source_oid, target_oid=target_oid,693                               comp_status=comp_status)694        return ajax_response(695            status=200,696            response={'source_ddl': sql['source_ddl'],697                      'target_ddl': sql['target_ddl'],698                      'diff_ddl': sql['diff_ddl']}699        )700 701    msg = gettext('Selected object is not supported for DDL comparison.')702 703    return ajax_response(704        status=200,705        response={'source_ddl': msg,706                  'target_ddl': msg,707                  'diff_ddl': msg708                  }709    )710 711 712def check_version_compatibility(sid, tid):713    """Check the version compatibility of source and target servers."""714 715    driver = get_driver(PG_DEFAULT_DRIVER)716    src_server = Server.query.filter_by(id=sid).first()717    src_manager = driver.connection_manager(src_server.id)718    src_conn = src_manager.connection()719 720    tar_server = Server.query.filter_by(id=tid).first()721    tar_manager = driver.connection_manager(tar_server.id)722    target_conn = tar_manager.connection()723 724    if not (src_conn.connected() and target_conn.connected()):725        return False, gettext('Server(s) disconnected.')726 727    if src_manager.server_type != tar_manager.server_type:728        return False, gettext('Schema diff does not support the comparison '729                              'between Postgres Server and EDB Postgres '730                              'Advanced Server.')731 732    def get_round_val(x):733        if x < 100000:734            return x + 100 - x % 100735        else:736            return x + 10000 - x % 10000737 738    if get_round_val(src_manager.version) == \739            get_round_val(tar_manager.version):740        return True, None741 742    return False, gettext('Source and Target database server must be of '743                          'the same major version.')744 745 746def get_schemas(sid, did):747    """748    This function will return the list of schemas for the specified749    server id and database id.750    """751    try:752        view = SchemaDiffRegistry.get_node_view('schema')753        server = Server.query.filter_by(id=sid).first()754        response = view.nodes(gid=server.servergroup_id, sid=sid, did=did,755                              is_schema_diff=True)756        schemas = json.loads(response.data)['data']757        return schemas758    except Exception as e:759        app.logger.exception(e)760 761    return None762 763 764def compare_database_objects(**kwargs):765    """766    This function is used to compare the specified schema and their children.767 768    :param kwargs:769    :return:770    """771    trans_id = kwargs.get('trans_id')772    session_obj = kwargs.get('session_obj')773    source_sid = kwargs.get('source_sid')774    source_did = kwargs.get('source_did')775    target_sid = kwargs.get('target_sid')776    target_did = kwargs.get('target_did')777    diff_model_obj = kwargs.get('diff_model_obj')778    total_percent = kwargs.get('total_percent')779    node_percent = kwargs.get('node_percent')780    ignore_owner = kwargs.get('ignore_owner')781    ignore_whitespaces = kwargs.get('ignore_whitespaces')782    ignore_tablespace = kwargs.get('ignore_tablespace')783    ignore_grants = kwargs.get('ignore_grants')784    comparison_result = []785 786    all_registered_nodes = SchemaDiffRegistry.get_registered_nodes(None,787                                                                   'Database')788    for node_name, node_view in all_registered_nodes.items():789        view = SchemaDiffRegistry.get_node_view(node_name)790        if hasattr(view, 'compare'):791            msg = gettext('Comparing {0}'). \792                format(gettext(view.blueprint.collection_label))793            app.logger.debug(msg)794            socketio.emit('compare_status', {'diff_percentage': total_percent,795                          'compare_msg': msg}, namespace=SOCKETIO_NAMESPACE,796                          to=request.sid)797            # Update the message and total percentage in session object798            update_session_diff_transaction(trans_id, session_obj,799                                            diff_model_obj)800 801            res = view.compare(source_sid=source_sid,802                               source_did=source_did,803                               target_sid=target_sid,804                               target_did=target_did,805                               group_name=gettext('Database Objects'),806                               ignore_owner=ignore_owner,807                               ignore_whitespaces=ignore_whitespaces,808                               ignore_tablespace=ignore_tablespace,809                               ignore_grants=ignore_grants)810 811            if res is not None:812                comparison_result = comparison_result + res813        total_percent = total_percent + node_percent814 815    return comparison_result, total_percent816 817 818def compare_schema_objects(**kwargs):819    """820    This function is used to compare the specified schema and their children.821 822    :param kwargs:823    :return:824    """825    trans_id = kwargs.get('trans_id')826    session_obj = kwargs.get('session_obj')827    source_sid = kwargs.get('source_sid')828    source_did = kwargs.get('source_did')829    source_scid = kwargs.get('source_scid')830    target_sid = kwargs.get('target_sid')831    target_did = kwargs.get('target_did')832    target_scid = kwargs.get('target_scid')833    schema_name = kwargs.get('schema_name')834    diff_model_obj = kwargs.get('diff_model_obj')835    total_percent = kwargs.get('total_percent')836    node_percent = kwargs.get('node_percent')837    is_schema_source_only = kwargs.get('is_schema_source_only', False)838    ignore_owner = kwargs.get('ignore_owner')839    ignore_whitespaces = kwargs.get('ignore_whitespaces')840    ignore_tablespace = kwargs.get('ignore_tablespace')841    ignore_grants = kwargs.get('ignore_grants')842 843    source_schema_name = None844    if is_schema_source_only:845        driver = get_driver(PG_DEFAULT_DRIVER)846        source_schema_name = driver.qtIdent(None, schema_name)847 848    comparison_result = []849 850    all_registered_nodes = SchemaDiffRegistry.get_registered_nodes()851    for node_name, node_view in all_registered_nodes.items():852        view = SchemaDiffRegistry.get_node_view(node_name)853        if hasattr(view, 'compare'):854            if schema_name == 'Schema Objects':855                msg = gettext('Comparing {0} '). \856                    format(gettext(view.blueprint.collection_label))857            else:858                msg = gettext('Comparing {0} of schema \'{1}\''). \859                    format(gettext(view.blueprint.collection_label),860                           gettext(schema_name))861            app.logger.debug(msg)862            socketio.emit('compare_status', {'diff_percentage': total_percent,863                          'compare_msg': msg}, namespace=SOCKETIO_NAMESPACE,864                          to=request.sid)865            # Update the message and total percentage in session object866            update_session_diff_transaction(trans_id, session_obj,867                                            diff_model_obj)868 869            res = view.compare(source_sid=source_sid,870                               source_did=source_did,871                               source_scid=source_scid,872                               target_sid=target_sid,873                               target_did=target_did,874                               target_scid=target_scid,875                               group_name=gettext(schema_name),876                               source_schema_name=source_schema_name,877                               ignore_owner=ignore_owner,878                               ignore_whitespaces=ignore_whitespaces,879                               ignore_tablespace=ignore_tablespace,880                               ignore_grants=ignore_grants)881 882            if res is not None:883                comparison_result = comparison_result + res884        total_percent = total_percent + node_percent885        # if total_percent is more than 100 then set it to less than 100886        if total_percent >= 100:887            total_percent = 96888 889    return comparison_result, total_percent890 891 892def fetch_compare_schemas(source_sid, source_did, target_sid, target_did):893    """894    This function is used to fetch all the schemas of source and target895    database and compare them.896 897    :param source_sid:898    :param source_did:899    :param target_sid:900    :param target_did:901    :return:902    """903    source_schemas = get_schemas(source_sid, source_did)904    target_schemas = get_schemas(target_sid, target_did)905 906    src_schema_dict = {item['label']: item['_id'] for item in source_schemas}907    tar_schema_dict = {item['label']: item['_id'] for item in target_schemas}908 909    dict1 = copy.deepcopy(src_schema_dict)910    dict2 = copy.deepcopy(tar_schema_dict)911 912    # Find the duplicate keys in both the dictionaries913    dict1_keys = set(dict1.keys())914    dict2_keys = set(dict2.keys())915    intersect_keys = dict1_keys.intersection(dict2_keys)916 917    # Keys that are available in source and missing in target.918    source_only = []919    added = dict1_keys - dict2_keys920    for item in added:921        source_only.append({'schema_name': item,922                            'scid': src_schema_dict[item]})923 924    target_only = []925    # Keys that are available in target and missing in source.926    removed = dict2_keys - dict1_keys927    for item in removed:928        target_only.append({'schema_name': item,929                            'scid': tar_schema_dict[item]})930 931    in_both_database = []932    for item in intersect_keys:933        in_both_database.append({'schema_name': item,934                                 'src_scid': src_schema_dict[item],935                                 'tar_scid': tar_schema_dict[item]})936 937    schema_result = {'source_only': source_only, 'target_only': target_only,938                     'in_both_database': in_both_database}939 940    return schema_result941 942 943def compare_pre_validation(trans_id, source_sid, target_sid):944    """945    This function is used to validate transaction id and version compatibility946    :param trans_id:947    :param source_sid:948    :param target_sid:949    :return:950    """951 952    status, error_msg, diff_model_obj, session_obj = \953        check_transaction_status(trans_id)954 955    if error_msg == ERROR_MSG_TRANS_ID_NOT_FOUND:956        res = make_json_response(success=0, errormsg=error_msg, status=404)957        return False, res, None, None958 959    # Server version compatibility check960    status, msg = check_version_compatibility(source_sid, target_sid)961    if not status:962        res = make_json_response(success=0, errormsg=msg, status=428)963        return False, res, None, None964 965    return True, '', diff_model_obj, session_obj966 967 968@socketio.on('connect', namespace=SOCKETIO_NAMESPACE)969def connect():970    """971    Connect to the server through socket.972    :return:973    :rtype:974    """975    socketio.emit('connected', {'sid': request.sid},976                  namespace=SOCKETIO_NAMESPACE,977                  to=request.sid)978 
codekingpro/portable-devtools · Team Ai