<commit_before>/*
 #
 # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
 # http://nexb.com and https://github.com/nexB/scancode-toolkit/
 # The ScanCode software is licensed under the Apache License version 2.0.
 # AboutCode is a trademark of nexB Inc.
 #
 # You may not use this software except in compliance with the License.
 # You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
 # Unless required by applicable law or agreed to in writing, software distributed
 # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 # CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
 #
 */

const HAS_A_VALUE =  "about_code_data_table_has_a_value";

class AboutCodeDataTable {
    constructor(tableID, aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
        this.dataTable = this._createDataTable(tableID);
    }

    database(aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
    }

    draw() {
        return this.dataTable.draw();
    }

    rows() {
        return this.dataTable.rows();
    }

    columns(columnId) {
        return this.dataTable.columns(columnId);
    }

    reload() {
        return this.dataTable.ajax.reload();
    }

    // This function is called every time DataTables needs to be redrawn.
    // For details on the parameters https://datatables.net/manual/server-side
    _query(dataTablesInput, dataTablesCallback) {
        // Sorting and Querying of data for DataTables
        this.aboutCodeDB.db.then(() => {
            let columnIndex = dataTablesInput.order[0].column;
            let columnName = dataTablesInput.columns[columnIndex].name;
            let direction = dataTablesInput.order[0].dir === "desc" ? "DESC" : "ASC";

            // query = {
            //   where: {
            //     $and: {
            //       path: { $like: "columnSearch%" },
            //       $or: [
            //         { path: { $like: "globalSearch%" } },
            //         { copyright_statements: { $like: "globalSearch%" } },
            //         ...,
            //       ]
            //     }
            //   }
            // }
            let query = {
                where: {
                    $and: {}
                },
                // Only take the chunk of data DataTables needs
                limit: dataTablesInput.length,
                offset: dataTablesInput.start,
                order: [[columnName, direction]]
            };

            // If a column search exists, add search for that column
            for (let i = 0; i < dataTablesInput.columns.length; i++) {
                let columnSearch = dataTablesInput.columns[i].search.value;
                if (columnSearch) {
                    const columnName = dataTablesInput.columns[i].name;

                    if (i === 0) {
                        // Column 0 is the "path", which should only match
                        // wildcards at the end of the path.
                        query.where.$and[columnName] = {
                            $like: `${columnSearch}%`
                        }
                    } else if (columnSearch === HAS_A_VALUE) {
                        // Return all non empty values
                        query.where.$and[columnName] = {
                            $and: [
                                { $ne: "[]" },
                                { $ne: "" },
                                { $ne: "{}" }
                            ]
                        }
                    } else {
                        query.where.$and[columnName] = {
                            $like: `%${columnSearch}%`
                        }
                    }
                }
            }

            // If a global search exists, add an $or search for each column
            let globalSearch = dataTablesInput.search.value;
            if (globalSearch) {
                query.where.$and.$or = [];
                for (let i = 0; i < dataTablesInput.columns.length; i++) {
                    let orSearch = {};
                    orSearch[dataTablesInput.columns[i].name] = {
                        $like: `%${globalSearch}%`
                    };
                    query.where.$and.$or.push(orSearch);
                }
            }

            // Execute the database find to get the rows of data
            let dFind = $.Deferred();
            this.aboutCodeDB.FlattenedFile.findAll(query)
                .then((result) => dFind.resolve(result));

            // Execute the database count of all rows
            let dCount = $.Deferred();
            this.aboutCodeDB.FlattenedFile.count({})
                .then((count) => dCount.resolve(count));

            // Execute the database count of filtered query rows
            let dFilteredCount = $.Deferred();
            this.aboutCodeDB.FlattenedFile.count(query)
                .then((count) => dFilteredCount.resolve(count));

            // Wait for all three of the Deferred objects to finish
            $.when(dFind, dCount, dFilteredCount)
                .then((rows, count, filteredCount) => {
                    dataTablesCallback({
                        draw: dataTablesInput.draw,
                        data: rows ? rows : [],
                        recordsFiltered: filteredCount,
                        recordsTotal: count
                    });
                });
        });
    }

    _createDataTable(tableID) {
        // Adds a footer for each column. This needs to be done before creating
        // the DataTable
        let cells = $.map(AboutCodeDataTable.TABLE_COLUMNS, () => "<td></td>")
            .join("");
        $(tableID).append("<tfoot><tr>" + cells + "</tr></tfoot>");
        let that = this;

        return $(tableID).DataTable({
            "info": false,
            "colReorder": true,
            "serverSide": true,
            "processing": true,
            "ajax": (dataTablesInput, dataTablesCallback) =>
                this._query(dataTablesInput, dataTablesCallback),
            "columns": AboutCodeDataTable.TABLE_COLUMNS,
            "fixedColumns": {
                leftColumns: 1
            },
            // TODO: We want to use scroller but the current version of the
            // plugin doesn't work with fixedColumns. Try updating
            // "scroller": true,
            "scrollX": true,
            "scrollResize": true,
            "deferRender": true,
            initComplete: function () {
                // Add a select element to each column's footer
                this.api().columns().every(function (columnIndex) {
                    const columnInfo = AboutCodeDataTable.TABLE_COLUMNS[columnIndex];

                    if ("skipFilter" in columnInfo && columnInfo.skipFilter) {
                        return;<commit_msg>Display fewer columns on load #3<commit_after>/*
 #
 # Copyright (c) 2017 nexB Inc. and others. All rights reserved.
 # http://nexb.com and https://github.com/nexB/scancode-toolkit/
 # The ScanCode software is licensed under the Apache License version 2.0.
 # AboutCode is a trademark of nexB Inc.
 #
 # You may not use this software except in compliance with the License.
 # You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
 # Unless required by applicable law or agreed to in writing, software distributed
 # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 # CONDITIONS OF ANY KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations under the License.
 #
 */

const HAS_A_VALUE =  "about_code_data_table_has_a_value";

class AboutCodeDataTable {
    constructor(tableID, aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
        this.dataTable = this._createDataTable(tableID);
    }

    database(aboutCodeDB) {
        this.aboutCodeDB = aboutCodeDB;
    }

    draw() {
        return this.dataTable.draw();
    }

    rows() {
        return this.dataTable.rows();
    }

    columns(columnId) {
        return this.dataTable.columns(columnId);
    }

    reload() {
        return this.dataTable.ajax.reload();
    }

    // This function is called every time DataTables needs to be redrawn.
    // For details on the parameters https://datatables.net/manual/server-side
    _query(dataTablesInput, dataTablesCallback) {
        // Sorting and Querying of data for DataTables
        this.aboutCodeDB.db.then(() => {
            let columnIndex = dataTablesInput.order[0].column;
            let columnName = dataTablesInput.columns[columnIndex].name;
            let direction = dataTablesInput.order[0].dir === "desc" ? "DESC" : "ASC";

            // query = {
            //   where: {
            //     $and: {
            //       path: { $like: "columnSearch%" },
            //       $or: [
            //         { path: { $like: "globalSearch%" } },
            //         { copyright_statements: { $like: "globalSearch%" } },
            //         ...,
            //       ]
            //     }
            //   }
            // }
            let query = {
                where: {
                    $and: {}
                },
                // Only take the chunk of data DataTables needs
                limit: dataTablesInput.length,
                offset: dataTablesInput.start,
                order: [[columnName, direction]]
            };

            // If a column search exists, add search for that column
            for (let i = 0; i < dataTablesInput.columns.length; i++) {
                let columnSearch = dataTablesInput.columns[i].search.value;
                if (columnSearch) {
                    const columnName = dataTablesInput.columns[i].name;

                    if (i === 0) {
                        // Column 0 is the "path", which should only match
                        // wildcards at the end of the path.
                        query.where.$and[columnName] = {
                            $like: `${columnSearch}%`
                        }
                    } else if (columnSearch === HAS_A_VALUE) {
                        // Return all non empty values
                        query.where.$and[columnName] = {
                            $and: [
                                { $ne: "[]" },
                                { $ne: "" },
                                { $ne: "{}" }
                            ]
                        }
                    } else {
                        query.where.$and[columnName] = {
                            $like: `%${columnSearch}%`
                        }
                    }
                }
            }

            // If a global search exists, add an $or search for each column
            let globalSearch = dataTablesInput.search.value;
            if (globalSearch) {
                query.where.$and.$or = [];
                for (let i = 0; i < dataTablesInput.columns.length; i++) {
                    let orSearch = {};
                    orSearch[dataTablesInput.columns[i].name] = {
                        $like: `%${globalSearch}%`
                    };
                    query.where.$and.$or.push(orSearch);
                }
            }

            // Execute the database find to get the rows of data
            let dFind = $.Deferred();
            this.aboutCodeDB.FlattenedFile.findAll(query)
                .then((result) => dFind.resolve(result));

            // Execute the database count of all rows
            let dCount = $.Deferred();
            this.aboutCodeDB.FlattenedFile.count({})
                .then((count) => dCount.resolve(count));

            // Execute the database count of filtered query rows
            let dFilteredCount = $.Deferred();
            this.aboutCodeDB.FlattenedFile.count(query)
                .then((count) => dFilteredCount.resolve(count));

            // Wait for all three of the Deferred objects to finish
            $.when(dFind, dCount, dFilteredCount)
                .then((rows, count, filteredCount) => {
                    dataTablesCallback({
                        draw: dataTablesInput.draw,
                        data: rows ? rows : [],
                        recordsFiltered: filteredCount,
                        recordsTotal: count
                    });
                });
        });
    }

    _createDataTable(tableID) {
        // Adds a footer for each column. This needs to be done before creating
        // the DataTable
        let cells = $.map(AboutCodeDataTable.TABLE_COLUMNS, () => "<td></td>")
            .join("");
        $(tableID).append("<tfoot><tr>" + cells + "</tr></tfoot>");
        let that = this;

        return $(tableID).DataTable({
            "info": false,
            "colReorder": true,
            "serverSide": true,
            "processing": true,
            "ajax": (dataTablesInput, dataTablesCallback) =>
                this._query(dataTablesInput, dataTablesCallback),
            "columns": AboutCodeDataTable.TABLE_COLUMNS,
            "columnDefs": [
                {
                    "targets": [ 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 25, 26, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47 ],
                    "visible": false
                },
                {
                    "targets": [ 0, 1, 8, 23, 24, 27, 28 ],
                    "visible": true
                }
            ],
            "fixedColumns": {
                leftColumns: 1
            },
            // TODO: We want to use scroller but the current version of the
            // plugin doesn't work with fixedColumns. Try updating
            // "scroller": true,
            "scrollX": true,
            "scrollResize": true,
            "deferRender": true,
            initComplete: function () {
                // Add a select element to each column's footer
                this.api().columns().every(function (columnIndex) {
                    const columnInfo = AboutCodeDataTable.TABLE_COLUMNS[columnIndex];

                    if ("skipFilter" in columnInfo && columnInfo.skipFilter) {
                        return;
{'fraction_non_alphanumeric': 0.10910868957809444, 'fraction_numerical': 0.008172673931265717, 'mean_word_length': 1.3676203075905409, 'pattern_counts': {'":': 27, '<': 19, '<?xml version=': 0, '>': 29, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 15, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1533967', 'n_tokens_mistral': 3796, 'n_tokens_neox': 3510, 'n_words': 975}