<commit_before>'use strict';

const Joi = require('joi');
const Postgres = require('pg').native;
const Schemas = require('./schemas');
const Config = require('./config');

const internals = {
    query: function (query, next) {

        Postgres.connect(Config.postgresURL, (connErr, client, done) => {

            if (connErr) {
                done();

                return next(connErr);
            }

            client.query(query, (queryErr, result) => {

                done();

                return next(queryErr, result);
            });
        });
    },
    read: function (id, query, next) {

        const err = Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query({
            text: query,
            values: [id]
        }, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rows);
        });
    },
    edit: function (id, schema, data, query, next) {

        const err = schema.validate(data).error ||
            Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query(query, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rowCount);
        });
    },
    add: function (schema, data, query, next) {

        const err = schema.validate(data).error;

        if (err) {

            return next(err);
        }

        internals.query(query, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rows);
        });
    },
    delete: function (id, table, next) {

        const err = Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query({
            text: `DELETE FROM ${table} WHERE id = $1`,
            values: [id]
        }, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rowCount);
        });
    }
};

internals.query(`
        CREATE TABLE IF NOT EXISTS authors (
            id               serial PRIMARY KEY,
            penName          varchar (100) NOT NULL,
            lastName         varchar (50),
            firstName        varchar (50)
        );
        CREATE TABLE IF NOT EXISTS books (
            id               serial PRIMARY KEY,
            title            varchar (300) NOT NULL,
            synopsis         varchar (1000),
            isbn10           bigint,
            isbn13           bigint,
            author           int NOT NULL
        );
    `, (err) => {

    if (err) {

        throw err;
    }
});


exports.authorModel = [
    {
        name: 'author.browse',
        method: function (query, sort, order, page, perPage, next) {

            const err = Schemas.page.validate(page).error ||
                Schemas.perPage.validate(perPage).error ||
                Schemas.order.validate(order).error ||
                Schemas.authorSort.validate(sort).error;

            if (err) {

                return next(err);
            }

            const values = [sort, perPage, (page - 1) * perPage];
            let filter = '';
            if (query) {
                values.push(query);
                filter = `WHERE penName like '%$4%' OR
                                lastName like '%$4%' OR
                                firstName like '%$4%' `;
            }

            internals.query({
                text: `SELECT * FROM authors ${filter}ORDER BY $1 ${order} LIMIT $2 OFFSET $3`,
                values: values
            }, (err, result) => {

                if (err) {

                    return next(err);
                }

                return next(null, result.rows);
            });
        }
    },
    {
        name: 'author.read',
        method: function (id, next) {

            return internals.read(id, 'SELECT * FROM authors WHERE id = $1', next);
        }
    },
    {
        name: 'author.edit',
        method: function (id, author, next) {

            const queryValues = [];
            let queryText = 'UPDATE authors SET';

            if (author.hasOwnProperty('penName')) {
                queryValues.push(author.penName);
                queryText = `${queryText} penName = $${queryValues.length}`;
            }

            if (author.hasOwnProperty('lastName')) {
                queryValues.push(author.lastName);
                queryText = `${queryText} lastName = $${queryValues.length}`;
            }

            if (author.hasOwnProperty('firstName')) {
                queryValues.push(author.firstName);
                queryText = `${queryText} firstName = $${queryValues.length}`;
            }

            queryValues.push(id);

            return internals.edit(id, Schemas.author, author, {
                text: `${queryText} WHERE id = $${queryValues.length}`,
                values: queryValues
            }, next);
        }
    },
    {
        name: 'author.add',
        method: function (author, next) {

            return internals.add(Schemas.author.requiredKeys('penName'), author, {
                text: 'INSERT INTO authors (penName, lastName, firstName) VALUES ($1, $2, $3) RETURNING id',
                values: [author.penName, author.lastName, author.firstName]
            }, next);
        }
    },
    {
        name: 'author.delete',
        method: function (id, next) {

            return internals.delete(id, 'authors', next);
        }
    }
];


exports.bookModel = [
    {
        name: 'book.browse',
        method: function (query, sort, order, page, perPage, author, next) {

            const err = Schemas.page.validate(page).error ||
                Schemas.perPage.validate(perPage).error ||
                Schemas.order.validate(order).error ||
                Schemas.bookSort.validate(sort).error;

            if (err) {

                return next(err);
            }

            const values = [sort, perPage, (page - 1) * perPage];
            let filter = '';

            if (author && !Schemas.id.validate(author).error) {
                values.push(author);
                filter = `books.author = $${values.length}`;
            }

            if (query && !Joi.string().validate(query).error) {
                values.push(query);

                if (filter) {
                    filter = `${filter} AND`;
                }

                filter = `${filter} books.title like '%$${values.length}%' OR
                                    books.isbn10 like '%$${values.length}%' OR
                                    books.isbn13 like '%$${values.length}%' OR
                                    books.synopsis like '%$${values.length}%'`;
            }

            if (filter) {
                filter = `WHERE ${filter}`;
            }

            internals.query({
                text: `SELECT   books.id,
                                books.title, 
                                books.synopsis,
                                books.isbn10,
                                books.isbn13,
                                authors.id as author,
                                authors.penName
                       FROM books INNER JOIN authors
                       ON books.author = authors.id
                       ${filter} ORDER BY $1 ${order} LIMIT $2 OFFSET $3`,
                values: values<commit_msg>fix issue with 'undefined' query<commit_after>'use strict';

const Joi = require('joi');
const Postgres = require('pg').native;
const Schemas = require('./schemas');
const Config = require('./config');

const internals = {
    query: function (query, next) {

        Postgres.connect(Config.postgresURL, (connErr, client, done) => {

            if (connErr) {
                done();

                return next(connErr);
            }

            client.query(query, (queryErr, result) => {

                done();

                return next(queryErr, result);
            });
        });
    },
    read: function (id, query, next) {

        const err = Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query({
            text: query,
            values: [id]
        }, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rows);
        });
    },
    edit: function (id, schema, data, query, next) {

        const err = schema.validate(data).error ||
            Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query(query, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rowCount);
        });
    },
    add: function (schema, data, query, next) {

        const err = schema.validate(data).error;

        if (err) {

            return next(err);
        }

        internals.query(query, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rows);
        });
    },
    delete: function (id, table, next) {

        const err = Schemas.id.validate(id).error;

        if (err) {

            return next(err);
        }

        internals.query({
            text: `DELETE FROM ${table} WHERE id = $1`,
            values: [id]
        }, (err, result) => {

            if (err) {

                return next(err);
            }

            return next(null, result.rowCount);
        });
    }
};

internals.query(`
        CREATE TABLE IF NOT EXISTS authors (
            id               serial PRIMARY KEY,
            penName          varchar (100) NOT NULL,
            lastName         varchar (50),
            firstName        varchar (50)
        );
        CREATE TABLE IF NOT EXISTS books (
            id               serial PRIMARY KEY,
            title            varchar (300) NOT NULL,
            synopsis         varchar (1000),
            isbn10           bigint,
            isbn13           bigint,
            author           int NOT NULL
        );
    `, (err) => {

    if (err) {

        throw err;
    }
});


exports.authorModel = [
    {
        name: 'author.browse',
        method: function (query, sort, order, page, perPage, next) {

            const err = Schemas.page.validate(page).error ||
                Schemas.perPage.validate(perPage).error ||
                Schemas.order.validate(order).error ||
                Schemas.authorSort.validate(sort).error;

            if (err) {

                return next(err);
            }

            const values = [sort, perPage, (page - 1) * perPage];
            let filter = '';
            if (query) {
                filter = `WHERE penName like '%${query}%' OR
                                lastName like '%${query}%' OR
                                firstName like '%${query}%' `;
            }

            internals.query({
                text: `SELECT * FROM authors ${filter}ORDER BY $1 ${order} LIMIT $2 OFFSET $3`,
                values: values
            }, (err, result) => {

                if (err) {

                    return next(err);
                }

                return next(null, result.rows);
            });
        }
    },
    {
        name: 'author.read',
        method: function (id, next) {

            return internals.read(id, 'SELECT * FROM authors WHERE id = $1', next);
        }
    },
    {
        name: 'author.edit',
        method: function (id, author, next) {

            const queryValues = [];
            let queryText = 'UPDATE authors SET';

            if (author.hasOwnProperty('penName')) {
                queryValues.push(author.penName);
                queryText = `${queryText} penName = $${queryValues.length}`;
            }

            if (author.hasOwnProperty('lastName')) {
                queryValues.push(author.lastName);
                queryText = `${queryText} lastName = $${queryValues.length}`;
            }

            if (author.hasOwnProperty('firstName')) {
                queryValues.push(author.firstName);
                queryText = `${queryText} firstName = $${queryValues.length}`;
            }

            queryValues.push(id);

            return internals.edit(id, Schemas.author, author, {
                text: `${queryText} WHERE id = $${queryValues.length}`,
                values: queryValues
            }, next);
        }
    },
    {
        name: 'author.add',
        method: function (author, next) {

            return internals.add(Schemas.author.requiredKeys('penName'), author, {
                text: 'INSERT INTO authors (penName, lastName, firstName) VALUES ($1, $2, $3) RETURNING id',
                values: [author.penName, author.lastName, author.firstName]
            }, next);
        }
    },
    {
        name: 'author.delete',
        method: function (id, next) {

            return internals.delete(id, 'authors', next);
        }
    }
];


exports.bookModel = [
    {
        name: 'book.browse',
        method: function (query, sort, order, page, perPage, author, next) {

            const err = Schemas.page.validate(page).error ||
                Schemas.perPage.validate(perPage).error ||
                Schemas.order.validate(order).error ||
                Schemas.bookSort.validate(sort).error;

            if (err) {

                return next(err);
            }

            const values = [sort, perPage, (page - 1) * perPage];
            let filter = '';

            if (author && !Schemas.id.validate(author).error) {
                values.push(author);
                filter = `books.author = $${values.length}`;
            }

            if (query && !Joi.string().validate(query).error) {
                if (filter) {
                    filter = `${filter} AND`;
                }
                filter = `${filter} books.title like '%${query}%' OR
                                    books.synopsis like '%${query}%'`;
            }

            if (filter) {
                filter = `WHERE ${filter}`;
            }

            internals.query({
                text: `SELECT   books.id,
                                books.title, 
                                books.synopsis,
                                books.isbn10,
                                books.isbn13,
                                authors.id as author,
                                authors.penName
                       FROM books INNER JOIN authors
                       ON books.author = authors.id
                       ${filter} ORDER BY $1 ${order} LIMIT $2 OFFSET $3`,
                values: values
{'fraction_non_alphanumeric': 0.1230789879873834, 'fraction_numerical': 0.005167438426951211, 'mean_word_length': 1.2318406469971543, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4573767', 'n_tokens_mistral': 4140, 'n_tokens_neox': 3872, 'n_words': 921}