/// <summary>
        ///     Loads the database.
        /// </summary>
        public void Load()
        {
            _cache.Clear();
            using (var reader = _connection.QueryReader("SELECT * FROM UserSpecificFunctions"))
            {
                while (reader.Read())
                {
                    var userId   = reader.Get <int>("UserId");
                    var chatData = new ChatInformation(reader.Get <string>("Prefix"), reader.Get <string>("Suffix"),
                                                       reader.Get <string>("Color"));

                    var player = new PlayerMetadata(userId, chatData);
                    using (var reader2 =
                               _connection.QueryReader("SELECT * FROM UserHasPermission WHERE UserId = @0", userId))
                    {
                        while (reader2.Read())
                        {
                            var permissionName = reader.Get <string>("Permission");
                            var isNegated      = reader.Get <int>("IsNegated") == 1;
                            player.Permissions.Add(new Permission(permissionName, isNegated));
                        }
                    }

                    _cache.Add(player);
                }
            }
        }
        /// <summary>
        ///     Updates the specified player's database information.
        /// </summary>
        /// <param name="playerInfo">The player, which must not be <c>null</c>.</param>
        public void Update([NotNull] PlayerMetadata playerInfo)
        {
            if (playerInfo == null)
            {
                throw new ArgumentNullException(nameof(playerInfo));
            }

            _connection.Query("UPDATE UserSpecificFunctions SET Prefix = @0, Suffix = @1, Color = @2 WHERE UserId = @3",
                              playerInfo.ChatData.Prefix, playerInfo.ChatData.Suffix, playerInfo.ChatData.Color, playerInfo.UserId);
            _connection.Query("DELETE FROM UserHasPermission WHERE UserId = @0", playerInfo.UserId);
            using (var db = _connection.CloneEx())
            {
                db.Open();
                using (var transaction = db.BeginTransaction())
                {
                    try
                    {
                        using (var command = (SqliteCommand)db.CreateCommand())
                        {
                            command.CommandText =
                                "INSERT INTO UserHasPermission (UserId, Permission, IsNegated) VALUES (@0, @1, @2)";
                            command.AddParameter("@0", playerInfo.UserId);
                            command.AddParameter("@1", null);
                            command.AddParameter("@2", null);

                            foreach (var permission in playerInfo.Permissions.GetAll()
                                     .Where(p => !string.IsNullOrWhiteSpace(p.Name)))
                            {
                                command.Parameters["@1"].Value = permission.Name;
                                command.Parameters["@2"].Value = permission.Negated ? 1 : 0;
                                command.ExecuteNonQuery();
                            }
                        }
                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        try
                        {
                            transaction.Rollback();
                        }
                        catch (Exception ex)
                        {
                            TShock.Log.ConsoleError(ex.ToString());
                        }
                    }
                }
            }

            var player = TShock.Players.SingleOrDefault(p => p?.User?.ID == playerInfo.UserId);

            player?.SetData(PlayerMetadata.PlayerInfoKey, playerInfo);
        }
        /// <summary>
        ///     Inserts a new object into the database.
        /// </summary>
        /// <param name="playerInfo">The object, which must not be <c>null</c>.</param>
        public void Add([NotNull] PlayerMetadata playerInfo)
        {
            if (playerInfo == null)
            {
                throw new ArgumentNullException(nameof(playerInfo));
            }

            _connection.Query(
                "INSERT INTO UserSpecificFunctions (UserId, Prefix, Suffix, Color) VALUES (@0, @1, @2, @3)",
                playerInfo.UserId, playerInfo.ChatData.Prefix, playerInfo.ChatData.Suffix, playerInfo.ChatData.Color);
            foreach (var permission in playerInfo.Permissions.GetAll().Where(p => !string.IsNullOrWhiteSpace(p.Name)))
            {
                _connection.Query("INSERT INTO UserHasPermission (UserId, Permission, IsNegated) VALUES (@0, @1, @2)",
                                  playerInfo.UserId, permission.Name, permission.Negated ? 1 : 0);
            }
        }