#pragma once #include "session.hpp" #include #include #include #include #include namespace ZShell::llm { class LlmClient; class ChatStore : public QObject { Q_OBJECT QML_ANONYMOUS Q_PROPERTY(int count READ count NOTIFY countChanged) Q_PROPERTY(QVariantList values READ values NOTIFY valuesChanged) public: explicit ChatStore(QObject* parent = nullptr); ~ChatStore() override; [[nodiscard]] int count() const; [[nodiscard]] QVariantList values() const; [[nodiscard]] ChatSession* at(int index) const; Q_INVOKABLE ZShell::llm::ChatSession* insert(int index = -1); Q_INVOKABLE void remove(int index); Q_INVOKABLE void remove(ZShell::llm::ChatSession* chat); Q_INVOKABLE void move(int from, int to); Q_INVOKABLE void clear(); [[nodiscard]] ChatSession* sessionById(const QString& id); [[nodiscard]] LlmClient* llmClient() const { return m_llmClient; } void setLlmClient(LlmClient* client); void persist(ChatSession* session); void saveMeta(ChatSession* session); // Loads the session's messages from the database. The SQL runs on a // worker thread; the object tree is built and the model updated on // the GUI thread when it arrives (ChatSession::loaded). void loadMessagesInto(ChatSession* session); Q_SIGNALS: void countChanged(); void valuesChanged(); void sessionRemoved(ZShell::llm::ChatSession* session); private: void openDb(); void load(); bool saveSession(ChatSession* session); void sortAndNotify(); void removeSession(ChatSession* session); void notify(const QList& before); QList m_sessions; LlmClient* m_llmClient = nullptr; QString m_connectionName; QString m_dbPath; // Sessions whose persist() ran before their messages finished // loading; persisted once the load lands. QSet m_pendingPersists; [[nodiscard]] QSqlDatabase db() const; }; } // namespace ZShell::llm