InternalLoadAllServerScopesInfosAsync(SyncContext context, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName);

            using var command = scopeBuilder.GetCommandAsync(DbScopeCommandType.GetAllServerScopesInfo, connection, transaction);

            if (command == null)
            {
                return(context, null);
            }

            var action = new ServerScopeInfoLoadingArgs(context, context.ScopeName, command, connection, transaction);

            await this.InterceptAsync(action, progress, cancellationToken).ConfigureAwait(false);

            if (action.Cancel || action.Command == null)
            {
                return(context, null);
            }

            var serverScopes = new List <ServerScopeInfo>();

            await this.InterceptAsync(new DbCommandArgs(context, action.Command, connection, transaction), progress, cancellationToken).ConfigureAwait(false);

            using DbDataReader reader = await action.Command.ExecuteReaderAsync().ConfigureAwait(false);

            while (reader.Read())
            {
                var scopeInfo = InternalReadServerScopeInfo(reader);

                if (scopeInfo.Schema != null)
                {
                    scopeInfo.Schema.EnsureSchema();
                }

                serverScopes.Add(scopeInfo);
            }

            reader.Close();

            foreach (var scopeInfo in serverScopes)
            {
                var scopeLoadedArgs = new ServerScopeInfoLoadedArgs(context, context.ScopeName, scopeInfo, connection, transaction);
                await this.InterceptAsync(scopeLoadedArgs, progress, cancellationToken).ConfigureAwait(false);
            }
            action.Command.Dispose();

            return(context, serverScopes);
        }
        InternalLoadServerScopeInfoAsync(SyncContext context, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName);

            using var command = scopeBuilder.GetCommandAsync(DbScopeCommandType.GetServerScopeInfo, connection, transaction);

            if (command == null)
            {
                return(context, null);
            }

            DbSyncAdapter.SetParameterValue(command, "sync_scope_name", context.ScopeName);

            var action = new ServerScopeInfoLoadingArgs(context, context.ScopeName, command, connection, transaction);

            await this.InterceptAsync(action, progress, cancellationToken).ConfigureAwait(false);

            if (action.Cancel || action.Command == null)
            {
                return(context, null);
            }

            await this.InterceptAsync(new DbCommandArgs(context, action.Command, connection, transaction), progress, cancellationToken).ConfigureAwait(false);

            using DbDataReader reader = await action.Command.ExecuteReaderAsync().ConfigureAwait(false);

            ServerScopeInfo serverScopeInfo = null;

            if (reader.Read())
            {
                serverScopeInfo = InternalReadServerScopeInfo(reader);
            }

            reader.Close();

            if (serverScopeInfo?.Schema != null)
            {
                serverScopeInfo.Schema.EnsureSchema();
            }

            var scopeLoadedArgs = new ServerScopeInfoLoadedArgs(context, context.ScopeName, serverScopeInfo, connection, transaction);

            await this.InterceptAsync(scopeLoadedArgs, progress, cancellationToken).ConfigureAwait(false);

            serverScopeInfo = scopeLoadedArgs.ServerScopeInfo;
            action.Command.Dispose();

            return(context, serverScopeInfo);
        }
        InternalGetServerScopeInfoAsync(SyncContext context, SyncSetup setup, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            try
            {
                await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.ScopeLoading, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                bool exists;
                (context, exists) = await this.InternalExistsScopeInfoTableAsync(context, DbScopeType.Server, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                if (!exists)
                {
                    await this.InternalCreateScopeInfoTableAsync(context, DbScopeType.Server, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);
                }

                (context, exists) = await this.InternalExistsScopeInfoTableAsync(context, DbScopeType.ServerHistory, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                if (!exists)
                {
                    await this.InternalCreateScopeInfoTableAsync(context, DbScopeType.ServerHistory, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);
                }

                ServerScopeInfo serverScopeInfo;
                (context, serverScopeInfo) = await this.InternalLoadServerScopeInfoAsync(context, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                if (serverScopeInfo == null)
                {
                    serverScopeInfo = this.InternalCreateScopeInfo(context.ScopeName, DbScopeType.Server) as ServerScopeInfo;

                    (context, serverScopeInfo) = await this.InternalSaveServerScopeInfoAsync(serverScopeInfo, context, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);
                }

                // Raise error only on server side, since we can't do nothing if we don't have any tables provisionned and no setup provided
                if ((serverScopeInfo.Setup == null || serverScopeInfo.Schema == null) && (setup == null || setup.Tables.Count <= 0))
                {
                    throw new MissingTablesException(context.ScopeName);
                }

                // if serverscopeinfo is a new, because we never run any sync before, grab schema and affect setup
                if (serverScopeInfo.Setup == null && serverScopeInfo.Schema == null && setup != null && setup.Tables.Count > 0)
                {
                    SyncSet schema;
                    (context, schema) = await this.InternalGetSchemaAsync(context, setup, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                    serverScopeInfo.Setup  = setup;
                    serverScopeInfo.Schema = schema;

                    // Checking if we have already some scopes
                    // Then gets the first scope to get the id
                    List <ServerScopeInfo> allScopes;
                    (context, allScopes) = await this.InternalLoadAllServerScopesInfosAsync(context, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                    if (allScopes.Count > 0)
                    {
                        // Get the first scope with an existing setup
                        var firstScope = allScopes.FirstOrDefault(sc => sc.Setup != null);

                        if (firstScope != null)
                        {
                            if (serverScopeInfo.Setup.TrackingTablesPrefix != firstScope.Setup.TrackingTablesPrefix)
                            {
                                throw new Exception($"Can't add a new setup with different tracking table prefix. Please use same tracking table prefix as your first setup ([\"{firstScope.Setup.TrackingTablesPrefix}\"])");
                            }

                            if (serverScopeInfo.Setup.TrackingTablesSuffix != firstScope.Setup.TrackingTablesSuffix)
                            {
                                throw new Exception($"Can't add a new setup with different tracking table suffix. Please use same tracking table suffix as your first setup ([\"{firstScope.Setup.TrackingTablesSuffix}\"])");
                            }

                            if (serverScopeInfo.Setup.TriggersPrefix != firstScope.Setup.TriggersPrefix)
                            {
                                throw new Exception($"Can't add a new setup with different trigger prefix. Please use same trigger prefix as your first setup ([\"{firstScope.Setup.TriggersPrefix}\"])");
                            }

                            if (serverScopeInfo.Setup.TriggersSuffix != firstScope.Setup.TriggersSuffix)
                            {
                                throw new Exception($"Can't add a new setup with different trigger suffix. Please use same trigger suffix as your first setup ([\"{firstScope.Setup.TriggersSuffix}\"])");
                            }
                        }
                    }

                    // Write scopes locally
                    (context, serverScopeInfo) = await this.InternalSaveServerScopeInfoAsync(serverScopeInfo, context, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false);

                    // override default value
                    serverScopeInfo.IsNewScope = true;

                    var scopeLoadedArgs = new ServerScopeInfoLoadedArgs(context, context.ScopeName, serverScopeInfo, runner.Connection, runner.Transaction);
                    await this.InterceptAsync(scopeLoadedArgs, progress, cancellationToken).ConfigureAwait(false);
                }

                if (setup != null && setup.Tables.Count > 0 && !serverScopeInfo.Setup.EqualsByProperties(setup))
                {
                    throw new Exception("Seems you are trying another Setup tables that what is stored in your server scope database. Please make a migration or create a new scope");
                }

                await runner.CommitAsync().ConfigureAwait(false);

                return(context, serverScopeInfo);
            }
            catch (Exception ex)
            {
                throw GetSyncError(context, ex);
            }
        }