def generate(self, goal_slot_selection_weights=None):
        """
        Generate a goal

        :param goal_slot_selection_weights: list of weights that bias the
                                            sampling of slots for constraints
        :return: a new goal
        """

        # If a goals file has been provided
        if self.goals:
            return random.choice(self.goals)

        # Randomly pick an item from the database
        cursor = self.database.SQL_connection.cursor()

        sql_command = "SELECT * FROM " + self.db_table_name + \
                      " WHERE ROWID == (" + \
                      str(random.randint(1, self.db_row_count)) + ");"

        cursor.execute(sql_command)
        db_result = cursor.fetchone()

        attempt = 0
        while attempt < 3 and not db_result:
            print('GoalGenerator: Database {0} appears to be empty!'
                  .format(self.database))
            print(f'Trying again (attempt {attempt} out of 3)...')

            sql_command = "SELECT * FROM " + self.db_table_name + \
                          " WHERE ROWID == (" + \
                          str(random.randint(1, self.db_row_count)) + ");"

            cursor.execute(sql_command)
            db_result = cursor.fetchone()

            attempt += 1

        if not db_result:
            raise LookupError('GoalGenerator: Database {0} appears to be '
                              'empty!'.format(self.database))

        result = dict(zip(self.slot_names, db_result))

        # Generate goal
        goal = Goal()

        # TODO: Sample from all available operators, not just '='
        # (where applicable)

        # Sample constraints from informable slots
        if goal_slot_selection_weights:
            # If a list of weights has been provided then do weighted sampling

            # Make sure that all slots have some weight. Flatten the
            # dictionaries in the process
            slot_weights = []
            half_min_weight = min(goal_slot_selection_weights.values()) / 2.0

            for s in self.ontology.ontology['informable']:
                if s in goal_slot_selection_weights:
                    slot_weights.append(goal_slot_selection_weights[s])
                else:
                    slot_weights.append(half_min_weight)

            inf_slots = \
                self.weighted_random_sample_no_replacement(
                    list(self.ontology.ontology['informable'].keys()),
                    slot_weights,
                    random.randint(2,
                                   len(self.ontology.ontology['informable'])))

            inf_slots.reverse()
        else:
            inf_slots = \
                random.sample(
                    list(self.ontology.ontology['informable'].keys()),
                    random.randint(2,
                                   len(self.ontology.ontology['informable'])))

        # Sample requests from requestable slots
        req_slots = random.sample(
            self.ontology.ontology['requestable'],
            random.randint(0, len(self.ontology.ontology['requestable'])))

        # Remove slots for which the user places constraints
        # Note: 'name' may or may not be in inf_slots here, and this is
        # randomness is desirable
        for slot in inf_slots:
            if slot in req_slots:
                req_slots.remove(slot)

        # Never ask for specific name unless it is the only constraint
        # if 'name' in inf_slots and len(inf_slots) > 1:
        if 'name' in inf_slots:
            inf_slots.remove('name')

        # Shuffle informable and requestable slots to create some variety
        # when pushing into the agenda.
        random.shuffle(inf_slots)
        random.shuffle(req_slots)

        for slot in inf_slots:
            # Check that the slot has a value in the retrieved item
            if slot in result and result[slot]:
                goal.constraints[slot] = \
                    DialogueActItem(slot, Operator.EQ, result[slot])

        for slot in req_slots:
            if slot in result:
                goal.requests[slot] = DialogueActItem(slot, Operator.EQ, '')

        return goal

        Generate a goal

        :param goal_slot_selection_weights: list of weights that bias the
                                            sampling of slots for constraints
        :return: a new goal
        
plato/agent/component/user_simulator/goal.py