UNPKG

@codenameryuu/adonis-datatable

Version:
357 lines (356 loc) 10.3 kB
import Request from './request.js'; import { HttpContext } from '@adonisjs/core/http'; import collect from 'collect.js'; import Config from './config.js'; import DataProcessor from './processor.js'; import Helper from './utils/helper.js'; import app from '@adonisjs/core/services/app'; import emitter from '@adonisjs/core/services/emitter'; export class DataTableAbstract { ctx; config; request; $columns = {}; $columnDef = { index: false, append: [], edit: [], filter: {}, order: {}, only: [], }; $extraColumns = []; totalRecords = 0; filteredRecords = 0; $skipTotalRecords = false; autoFilter = true; filterCallback = null; $templates = { DT_RowId: '', DT_RowClass: '', DT_RowData: {}, DT_RowAttr: {}, }; orderCallback = null; $skipPaging = false; appends = {}; $editOnlySelectedColumns = false; $dataObject = true; $queryLogging = []; constructor() { this.config = new Config(app.config.get('datatables')); emitter.on('db:query', (query) => { this.$queryLogging.push({ query: query.sql, bindings: query.bindings, time: `${query.duration}ms`, }); }); } static canCreate(_source) { return false; } static create(source) { return new this(source); } prepareContext() { if (this.ctx) { return; } this.ctx = this.ctx ? this.ctx : HttpContext.getOrFail(); this.request = new Request(this.ctx.request); } async totalCount() { const total = await this.count(); return this.totalRecords ? this.totalRecords : total; } isBlacklisted(column) { const columnDef = this.getColumnsDefinition(); if (columnDef['blacklist'].includes(column)) { return true; } if (columnDef['whitelist'] === '*' || (columnDef['whitelist'] && columnDef['whitelist'].includes(column))) { return false; } return true; } async filterRecords() { if (this.autoFilter && this.request.isSearchable()) { this.filtering(); } if (typeof this.filterCallback === 'function') { this.filterCallback(this.resolveCallback()); } this.columnSearch(); await this.filteredCount(); } smartGlobalSearch(keyword) { const self = this; collect(keyword.split(' ')) .reject((text) => text.trim() === '') .each((text) => self.globalSearch(text)); } async filteredCount() { const total = await this.count(); return (this.filteredRecords = this.filteredRecords ? this.filteredRecords : total); } paginate() { if (this.request.isPaginationable() && !this.$skipPaging) { this.paging(); } } processResults(results) { const processor = new DataProcessor(results, this.getColumnsDefinition(), this.$templates, this.request.start(), this.config); return processor.process(this.$dataObject); } render(data) { let result = this.attachAppends({ draw: this.request.draw(), recordsTotal: this.totalRecords, recordsFiltered: this.filteredRecords ?? 0, data: data, }); if (this.config.isDebugging()) { result = this.showDebugger(result); } return result; } attachAppends(data) { return { ...data, ...this.appends }; } showDebugger(output) { output['queries'] = this.$queryLogging; output['input'] = this.request.all(); return output; } errorResponse(exception) { emitter.clearListeners('db:query'); if (!this.ctx) { return; } const result = { draw: this.request.draw(), recordsTotal: this.totalRecords, recordsFiltered: 0, data: [], error: `Exception Message: ${exception.stack}`, }; return result; } setupKeyword(value) { if (this.config.isSmartSearch()) { let keyword = `%${value}%}`; if (this.config.isWildcard()) { keyword = Helper.wildcardString(value, '%'); } return keyword.replace('\\', '%'); } return value; } getColumnName(index, wantsAlias = false) { let column = this.request.columnName(index); if (column === null || column === undefined) { return null; } if (Number.isInteger(column)) { column = this.getColumnNameByIndex(index); } if (Helper.contains(column.toUpperCase(), ' AS ')) { column = Helper.extractColumnName(column, wantsAlias); } return column; } getColumnNameByIndex(index) { const name = this.$columns[index] !== undefined && this.$columns[index] !== '*' ? this.$columns[index] : this.getPrimaryKeyName(); return this.$extraColumns.includes(name) ? this.getPrimaryKeyName() : name; } getPrimaryKeyName() { return 'id'; } setContext(ctx) { this.ctx = ctx; this.request = new Request(this.ctx.request); return this; } addColumn(name, content, order = false) { this.$extraColumns.push(name); this.$columnDef['append'].push({ name: name, content: content, order: order, }); return this; } addIndexColumn() { this.$columnDef['index'] = true; return this; } editColumn(name, content) { if (this.$editOnlySelectedColumns) { if (!this.request.columns().length || this.request .columns() .map((column) => column.name) .includes(name)) { this.$columnDef['edit'].push({ name: name, content: content, }); } } else { this.$columnDef['edit'].push({ name: name, content: content, }); } return this; } removeColumn(...names) { this.$columnDef.excess = [...this.getColumnsDefinition()['access'], ...names]; return this; } getColumnsDefinition() { const datatableColumns = this.config.get('columns'); const allowed = ['excess', 'escape', 'raw', 'blacklist', 'whitelist']; return Helper.objectReplaceRecursive(Helper.objectIntersectKey(datatableColumns, allowed), this.$columnDef); } only(columns = []) { this.$columnDef['only'] = columns; return this; } escapeColumns(columns = '*') { this.$columnDef['escape'] = columns; return this; } rawColumns(columns, merge = false) { if (merge) { const datatableColumns = this.config.get('columns'); this.$columnDef['raw'] = [...datatableColumns.raw, ...columns]; } else { this.$columnDef['raw'] = columns; } return this; } setRowClass(content) { this.$templates['DT_RowClass'] = content; return this; } setRowId(content) { this.$templates['DT_RowId'] = content; return this; } setRowData(data) { this.$templates['DT_RowData'] = data; return this; } addRowData(key, value) { this.$templates['DT_RowData'][key] = value; return this; } setRowAttr(data) { this.$templates['DT_RowAttr'] = data; return this; } addRowAttr(key, value) { this.$templates['DT_RowAttr'][key] = value; return this; } with(key, value = '') { if (Array.isArray(key)) { this.appends = key; } else { this.appends[key] = Helper.value(value); } return this; } withQuery(key, callback) { this.appends[key] = callback; return this; } order(callback) { this.orderCallback = callback; return this; } blacklist(blacklist) { this.$columnDef['blacklist'] = blacklist; return this; } whitelist(whitelist = '*') { this.$columnDef['whitelist'] = whitelist; return this; } smart(state = true) { this.config.set('datatables.search.smart', state); return this; } startsWithSearch(state = true) { this.config.set('datatables.search.starts_with', state); return this; } setTotalRecords(total) { this.totalRecords = total; return this; } skipTotalRecords() { this.totalRecords = 0; this.$skipTotalRecords = true; return this; } setFilteredRecords(total) { this.filteredRecords = total; return this; } skipPaging() { this.$skipPaging = true; return this; } pushToBlacklist(column) { if (!this.isBlacklisted(column)) { if (this.$columnDef['blacklist'] === undefined) { this.$columnDef['blacklist'] = []; } this.$columnDef['blacklist'].push(column); } return this; } filtering() { const keyword = this.request.keyword(); if (this.config.isMultiTerm()) { this.smartGlobalSearch(keyword); return; } this.globalSearch(keyword); } editOnlySelectedColumns() { this.$editOnlySelectedColumns = true; return this; } ordering() { if (typeof this.orderCallback === 'function') { this.orderCallback(this.resolveCallback()); return; } else { this.defaultOrdering(); } } filter(callback, globalSearch = false) { this.filterCallback = callback; this.autoFilter = globalSearch; return this; } asJson() { this.$dataObject = true; return this; } asArray() { this.$dataObject = false; return this; } }