UNPKG

@codenameryuu/adonis-datatable

Version:
283 lines (282 loc) 10.6 kB
import collect, { Collection } from "collect.js"; import lodash from "lodash"; import { DataTableAbstract } from "../datatable_abstract.js"; import Helper from "../utils/helper.js"; export default class ObjectDataTable extends DataTableAbstract { items; $offset = 0; constructor(items) { super(); this.items = items; this.$columns = collect(this.items).keys(); } static canCreate(source) { return typeof source === "object" || source instanceof Collection; } resolveCallback() { return this; } defaultOrdering() { const self = this; const orderable = this.request.orderableColumns(); if (orderable.length) { this.items = collect(this.items) .map((data) => Helper.dot(data)) .sort((a, b) => { for (const value of Object.values(orderable)) { const column = self.getColumnName(value["column"]); const direction = value["direction"]; let first; let second; let cmp = 0; if (direction === "desc") { first = b; second = a; } else { first = a; second = b; } if (Number.isInteger(first[column] ?? null) && Number.isInteger(second[column] ?? null)) { if (first[column] < second[column]) { cmp = -1; } else if (first[column] > second[column]) { cmp = 1; } } else if (self.config.isCaseInsensitive()) { const collator = new Intl.Collator(undefined, { sensitivity: "base", numeric: true }); cmp = collator.compare(first[column], second[column]); } else { const collator = new Intl.Collator(undefined, { sensitivity: "variant", numeric: true, }); cmp = collator.compare(first[column], second[column]); } return cmp; } return 0; }) .map((data) => { for (const [index, value] of Object.entries(data)) { lodash.unset(data, index); lodash.set(data, index, value); } return data; }) .all(); } } revertIndexColumn() { if (this.$columnDef["index"]) { const indexColumn = this.config.get("datatables.index_column", "DT_RowIndex"); const index = this.$dataObject ? indexColumn : 0; let start = this.request.start(); collect(this.items).transform((data) => { data[index] = ++start; return data; }); } } async count() { return collect(this.items).count(); } async results() { try { this.prepareContext(); this.totalRecords = await this.totalCount(); if (this.totalRecords) { const results = this.dataResults(); const processed = this.processResults(results); const output = lodash.transform(processed, (result, value, key) => { if (value) { result[key] = value; } }); this.items = collect(output).all(); this.ordering(); await this.filterRecords(); this.paginate(); this.revertIndexColumn(); } return this.render(collect(this.items).all()); } catch (error) { return this.errorResponse(error); } } dataResults() { return collect(this.items).all(); } setOffset(offset) { this.$offset = offset; return this; } columnSearch() { const self = this; for (let i = 0, c = this.request.columns().length; i < c; i++) { const column = this.getColumnName(i); if (column === null) { continue; } if (this.isBlacklisted(column)) { continue; } if (this.request.hasColumnControl(i) && this.request.isColumnSearchable(i, false)) { this.applyColumnControlSearch(i, column); continue; } if (!this.request.isColumnSearchable(i)) { continue; } const regex = this.request.isRegex(i); const keyword = this.request.columnKeyword(i); this.items = collect(this.items) .filter((row) => { const value = lodash.get(row, column); if (self.config.isCaseInsensitive()) { if (regex) { return new RegExp(keyword, "i").test(value); } return Helper.contains(value.toLowerCase(), keyword.toLowerCase()); } if (regex) { return new RegExp(keyword).test(value); } return Helper.contains(value, keyword); }) .all(); } } /** * Apply the search conditions sent by the DataTables ColumnControl extension. * * @see https://datatables.net/extensions/columncontrol/server-side */ applyColumnControlSearch(index, column) { const self = this; if (this.request.hasColumnControlList(index)) { const list = this.request.columnControlList(index).map((value) => self.normalizeColumnControl(value)); this.items = collect(this.items) .filter((row) => list.includes(self.normalizeColumnControl(lodash.get(row, column)))) .all(); } const search = this.request.columnControlSearch(index); if (search && (search.value !== "" || search.logic === "empty" || search.logic === "notEmpty")) { this.items = collect(this.items) .filter((row) => self.matchColumnControl(lodash.get(row, column), search)) .all(); } } normalizeColumnControl(value) { const text = value === null || value === undefined ? "" : String(value); return this.config.isCaseInsensitive() ? text.toLowerCase() : text; } matchColumnControl(raw, search) { const logic = search.logic; const isEmpty = raw === null || raw === undefined || String(raw) === ""; if (logic === "empty") { return isEmpty; } if (logic === "notEmpty") { return !isEmpty; } if (search.type === "num") { const left = Number(raw); const right = Number(search.value); if (Number.isNaN(left) || Number.isNaN(right)) { return false; } switch (logic) { case "notEqual": return left !== right; case "greater": return left > right; case "greaterOrEqual": return left >= right; case "less": return left < right; case "lessOrEqual": return left <= right; case "equal": default: return left === right; } } if (search.type === "date") { const dateOnly = !!search.mask && !/[Hhms]/.test(search.mask); const left = this.toTimestamp(raw, dateOnly); const right = this.toTimestamp(search.value, dateOnly); if (Number.isNaN(left) || Number.isNaN(right)) { return false; } switch (logic) { case "notEqual": return left !== right; case "greater": return left > right; case "less": return left < right; case "equal": default: return left === right; } } const haystack = this.normalizeColumnControl(raw); const needle = this.normalizeColumnControl(search.value); switch (logic) { case "equal": return haystack === needle; case "notEqual": return haystack !== needle; case "starts": return haystack.startsWith(needle); case "ends": return haystack.endsWith(needle); case "notContains": return !haystack.includes(needle); case "contains": default: return haystack.includes(needle); } } toTimestamp(value, dateOnly) { const date = new Date(value); if (Number.isNaN(date.getTime())) { return Number.NaN; } if (dateOnly) { return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime(); } return date.getTime(); } paging() { const offset = this.request.start() - this.$offset; const length = this.request.length() > 0 ? this.request.length() : 10; this.items = collect(this.items).slice(offset, length).all(); } globalSearch(keyword) { keyword = this.config.isCaseInsensitive() ? keyword.toLowerCase() : keyword; this.items = collect(this.items) .filter((row) => { for (const index of Object.values(this.request.searchableColumnIndex())) { const column = this.getColumnName(index); let value = lodash.get(row, column); if (typeof value !== "string") { continue; } else { value = this.config.isCaseInsensitive() ? value.toLowerCase() : value; } if (Helper.contains(value, keyword)) { return true; } } return false; }) .all(); } }