#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <pqxx/pqxx>

using namespace std;
using namespace pqxx;

struct Book {
    int id;
    string title;
    string author;
    int publication_year;
    string genre;
};

class BookDatabase {
public:
    BookDatabase(const string& connection_string)
        : conn_(connection_string) {}

    vector<Book> query_books_by_author(const string& author) {
        return query_books("author", author);
    }

    vector<Book> query_books_by_publication_year_range(int start_year, int end_year) {
        stringstream condition;
        condition << "publication_year BETWEEN " << start_year << " AND " << end_year;
        return query_books(condition.str());
    }

    vector<Book> query_books_by_genre(const string& genre) {
        return query_books("genre", genre);
    }

private:
    connection conn_;

    vector<Book> query_books(const string& column, const string& value) {
        stringstream sql;
        sql << "SELECT * FROM books WHERE " << column << " = " << quote(value) << ";";
        return execute_query(sql.str());
    }

    vector<Book> query_books(const string& condition) {
        stringstream sql;
        sql << "SELECT * FROM books WHERE " << condition << ";";
        return execute_query(sql.str());
    }

    vector<Book> execute_query(const string& sql) {
        work txn(conn_);
        result res = txn.exec(sql);
        txn.commit();

        vector<Book> books;
        for (const auto& row : res) {
            books.push_back({
                row["id"].as<int>(),
                row["title"].as<string>(),
                row["author"].as<string>(),
                row["publication_year"].as<int>(),
                row["genre"].as<string>()
            });
        }
        return books;
    }
};

void print_books(const vector<Book>& books) {
    if (books.empty()) {
        cout << "No results found." << endl;
        return;
    }

    for (const auto& book : books) {
        cout << "[" << book.id << "] "
             << book.title << " by " << book.author
             << ", published in " << book.publication_year
             << ", genre: " << book.genre << endl;
    }
}

int main() {
    // Replace with your own PostgreSQL connection string.
    const string connection_string = "dbname=mydb user=myuser password=mypassword host=localhost port=5432";

    BookDatabase db(connection_string);

    while (true) {
        cout << "\nChoose an option:\n"
             << "1. Query by author\n"
             << "2. Query by publication year range\n"
             << "3. Query by genre\n"
             << "4. Exit\n"
             << "> ";

        int choice;
        cin >> choice;

        vector<Book> results;

        switch (choice) {
        case 1:
            {
                cout << "Enter author name: ";
                string author;
                cin.ignore();
                getline(cin, author);
                results = db.query_books_by_author(author);
                break;
            }
        case 2:
            {
                int start_year, end_year;
                cout << "Enter start year: ";
                cin >> start_year;
                cout << "Enter end year: ";
                cin >> end_year;
                results = db.query_books_by_publication_year_range(start_year, end_year);
                break;
            }
        case 3:
            {
                cout << "Enter genre: ";
                string genre;
                cin.ignore();
                getline(cin, genre);
                results = db.query_books_by_genre(genre);
                break;
            }
        case 4:
            return 0;

        default:
            cout << "Invalid option. Try again." << endl;
            continue;
        }

        print_books(results);
    }

    return 0;
}
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
#include <pqxx/pqxx>

using namespace std;
using namespace pqxx;

struct Book {
    int id;
    string title;
    string author;
    int publication_year;
    string genre;
};

class BookDatabase {
public:
    BookDatabase(const string& connection_string)
        : conn_(connection_string) {}

    vector<Book> query_books_by_author(const string& author) {
        return query_books("author", author);
    }

    vector<Book> query_books_by_publication_year_range(int start_year, int end_year) {
        stringstream condition;
        condition << "publication_year BETWEEN " << start_year << " AND " << end_year;
        return query_books(condition.str());
    }

    vector<Book> query_books_by_genre(const string& genre) {
        return query_books("genre", genre);
    }

private:
    connection conn_;

    vector<Book> query_books(const string& column, const string& value) {
        stringstream sql;
        sql << "SELECT * FROM books WHERE " << column << " = " << quote(value) << ";";
        return execute_query(sql.str());
    }

    vector<Book> query_books(const string& condition) {
        stringstream sql;
        sql << "SELECT * FROM books WHERE " << condition << ";";
        return execute_query(sql.str());
    }

    vector<Book> execute_query(const string& sql) {
        work txn(conn_);
        result res = txn.exec(sql);
        txn.commit();

        vector<Book> books;
        for (const auto& row : res) {
            books.push_back({
                row["id"].as<int>(),
                row["title"].as<string>(),
                row["author"].as<string>(),
                row["publication_year"].as<int>(),
                row["genre"].as<string>()
            });
        }
        return books;
    }
};

void print_books(const vector<Book>& books) {
    if (books.empty()) {
        cout << "No results found." << endl;
        return;
    }

    for (const auto& book : books) {
        cout << "[" << book.id << "] "
             << book.title << " by " << book.author
             << ", published in " << book.publication_year
             << ", genre: " << book.genre << endl;
    }
}

int main() {
    // Replace with your own PostgreSQL connection string.
    const string connection_string = "dbname=mydb user=myuser password=mypassword host=localhost port=5432";

    BookDatabase db(connection_string);

    while (true) {
        cout << "\nChoose an option:\n"
             << "1. Query by author\n"
             << "2. Query by publication year range\n"
             << "3. Query by genre\n"
             << "4. Exit\n"
             << "> ";

        int choice;
        cin >> choice;

        vector<Book> results;

        switch (choice) {
        case 1:
            {
                cout << "Enter author name: ";
                string author;
                cin.ignore();
                getline(cin, author);
                results = db.query_books_by_author(author);
                break;
            }
        case 2:
            {
                int start_year, end_year;
                cout << "Enter start year: ";
                cin >> start_year;
                cout << "Enter end year: ";
                cin >> end_year;
                results = db.query_books_by_publication_year_range(start_year, end_year);
                break;
            }
        case 3:
            {
                cout << "Enter genre: ";
                string genre;
                cin.ignore();
                getline(cin, genre);
                results = db.query_books_by_genre(genre);
                break;
            }
        case 4:
            return 0;

        default:
            cout << "Invalid option. Try again." << endl;
            continue;
        }

        print_books(results);
    }

    return 0;
}