diff --git a/package-lock.json b/package-lock.json index 07cdb72..f4aec43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { "name": "seatable-api", - "version": "1.0.30", + "version": "1.0.31", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "seatable-api", - "version": "1.0.30", + "version": "1.0.31", "license": "ISC", "dependencies": { "@babel/runtime": "7.20.13", - "axios": "0.23.0" + "axios": "0.23.0", + "dayjs": "1.11.10" }, "devDependencies": { "@babel/cli": "7.15.7", @@ -3414,6 +3415,11 @@ "node": ">=10" } }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "node_modules/debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", @@ -10458,6 +10464,11 @@ "whatwg-url": "^8.0.0" } }, + "dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "debug": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", diff --git a/package.json b/package.json index 0698ffb..d601e2e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "homepage": "https://github.com/seatable/seatable-api-js#readme", "dependencies": { "@babel/runtime": "7.20.13", - "axios": "0.23.0" + "axios": "0.23.0", + "dayjs": "1.11.10" }, "devDependencies": { "@babel/cli": "7.15.7", diff --git a/src/base.js b/src/base.js index 05c5b21..a218d61 100644 --- a/src/base.js +++ b/src/base.js @@ -1,5 +1,5 @@ import axios from "axios"; -import { getAccessToken } from './utils'; +import { formatQueryResult, getAccessToken } from './utils'; class Base { @@ -365,7 +365,10 @@ class Base { query(sql) { const url = `api/v1/dtables/${this.dtableUuid}/query/`; const data = {sql: sql}; - return this.req.post(url, {...data}); + return this.req.post(url, {...data}).then(res => { + const result = res.data; + return Promise.resolve(formatQueryResult(result)); + }); } } diff --git a/src/constants.js b/src/constants.js index 43f9081..8d509a8 100644 --- a/src/constants.js +++ b/src/constants.js @@ -10,6 +10,7 @@ const ColumnTypes = { FILE: 'file', COLLABORATOR: 'collaborator', LINK: 'link', + LINK_FORMULA: 'link-formula', FORMULA: 'formula', CREATOR: 'creator', CTIME: 'ctime', @@ -20,7 +21,14 @@ const ColumnTypes = { URL: 'url', }; +const DATE_FORMAT_MAP = { + YYYY_MM_DD: 'YYYY-MM-DD', + YYYY_MM_DD_HH_MM: 'YYYY-MM-DD HH:mm', + YYYY_MM_DD_HH_MM_SS: 'YYYY-MM-DD HH:mm:ss' +}; + export { - ColumnTypes + ColumnTypes, + DATE_FORMAT_MAP, }; \ No newline at end of file diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100644 index 0000000..5eea22b --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,53 @@ +import dayjs from 'dayjs'; + +/** + * Get formatted date + * @param {string} date e.g. "2023-07-06 11:30" + * @param {string} format e.g. "YYYY-MM-DD" + * @returns formatted date, string + */ +const getDateDisplayString = (date, format) => { + if (!date || typeof date !== 'string') { + return ''; + } + + const dateObj = dayjs(date); + if (!dateObj.isValid()) return date; + switch (format) { + case 'D/M/YYYY': + case 'DD/MM/YYYY': { + const formatValue = dateObj.format('YYYY-MM-DD'); + const formatValueList = formatValue.split('-'); + return `${formatValueList[2]}/${formatValueList[1]}/${formatValueList[0]}`; + } + case 'D/M/YYYY HH:mm': + case 'DD/MM/YYYY HH:mm': { + const formatValues = dateObj.format('YYYY-MM-DD HH:mm'); + const formatValuesList = formatValues.split(' '); + const formatDateList = formatValuesList[0].split('-'); + return `${formatDateList[2]}/${formatDateList[1]}/${formatDateList[0]} ${formatValuesList[1]}`; + } + case 'M/D/YYYY': + return dateObj.format('M/D/YYYY'); + case 'M/D/YYYY HH:mm': + return dateObj.format('M/D/YYYY HH:mm'); + case 'YYYY-MM-DD': + return dateObj.format('YYYY-MM-DD'); + case 'YYYY-MM-DD HH:mm': + return dateObj.format('YYYY-MM-DD HH:mm'); + case 'YYYY-MM-DD HH:mm:ss': { + return dateObj.format('YYYY-MM-DD HH:mm:ss'); + } + case 'DD.MM.YYYY': + return dateObj.format('DD.MM.YYYY'); + case 'DD.MM.YYYY HH:mm': + return dateObj.format('DD.MM.YYYY HH:mm'); + default: + // Compatible with older versions: if format is null, use defaultFormat + return dateObj.format('YYYY-MM-DD'); + } +}; + +export { + getDateDisplayString, +}; diff --git a/src/utils/index.js b/src/utils/index.js index 139ba4f..86408b3 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -1,4 +1,6 @@ import axios from "axios"; +import { ColumnTypes } from "../constants"; +import { getDateDisplayString } from "./date"; const getAccessToken = (config) => { const { server, APIToken } = config; @@ -7,6 +9,69 @@ const getAccessToken = (config) => { return axios.get(url, { headers: headers }); }; +const formatQueryResult = (result) => { + const { meta_data, results } = result; + const columnMap = meta_data.map(column => { + if (column.type === ColumnTypes.SINGLE_SELECT || column.type === ColumnTypes.MULTIPLE_SELECT) { + const { options = [] } = column.data || {}; + let options_map = {}; + options.forEach(option => { + options_map[option.id] = option.name; + }); + column.options_map = options_map; + } + return { [column.key]: column }; + }); + + let rows = []; + for (let i = 0; i < results.length; i++) { + const row = results[i]; + const newRow = {}; + newRow['_id'] = row._id; + Object.keys(row).forEach(key => { + if (columnMap[key]) { + const { name, type, options_map, data = {} } = columnMap[key]; + let cellValue = row[key]; + switch(type) { + case ColumnTypes.SINGLE_SELECT: { + cellValue = options_map[cellValue]; + break; + } + case ColumnTypes.MULTIPLE_SELECT: { + if (!Array.isArray(cellValue)) return []; + cellValue = cellValue.map(key => options_map[key]); + break; + } + case ColumnTypes.LINK: + case ColumnTypes.LINK_FORMULA: { + if (!Array.isArray(cellValue)) { + cellValue = cellValue && cellValue.display_value; + } else { + cellValue = cellValue.map(item => item.display_value); + } + break; + } + case ColumnTypes.DATE: { + if (cellValue) { + const { format } = data; + cellValue = getDateDisplayString(cellValue, format); + } + break; + } + default: { + cellValue = row[key]; + break; + } + } + newRow[name] = cellValue; + } + }); + rows.push(newRow); + } + return rows; +} + export { - getAccessToken + getAccessToken, + formatQueryResult }