UNPKG

@tableau/taco-toolkit

Version:
367 lines 23.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __asyncValues = (this && this.__asyncValues) || function (o) { if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); var m = o[Symbol.asyncIterator], i; return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } }; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isFileEmpty = exports.composeDataRowsWithTypeFromObjectArray = exports.isValidDataRows = exports.composeDataRowsWithType = exports.composeDataRows = void 0; var fs_1 = __importDefault(require("fs")); var column_header_property_1 = require("../../shared/enums/column-header-property"); /** * Convert array type data into key-value pair DataRow array. * * The function uses array index to align data and column name. */ function composeDataRows(rows, columnNames) { var e_1, _a; var dataRows = []; try { for (var rows_1 = __values(rows), rows_1_1 = rows_1.next(); !rows_1_1.done; rows_1_1 = rows_1.next()) { var row = rows_1_1.value; var dataRow = {}; for (var index = 0; index < columnNames.length; index++) { var columnName = columnNames[index]; dataRow[columnName] = row[index]; } dataRows.push(dataRow); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (rows_1_1 && !rows_1_1.done && (_a = rows_1.return)) _a.call(rows_1); } finally { if (e_1) throw e_1.error; } } return dataRows; } exports.composeDataRows = composeDataRows; /** * Convert array type data into key-value pair DataRow array with column metadata. * The function uses array index to align data and column name. * * The result will only contain the columns that exists in the columnMetadata. * The data values will be converted into into corresponding type based on columnMetadata. * * - rows and columnNames determine the alignment and the order * - columnMetadata determines the selected column and the data value type */ function composeDataRowsWithType(rows, columnNames, columnMetadata) { var e_2, _a, e_3, _b; var dataRows = []; var filteredColumns = []; columnNames.forEach(function (columnName, index) { var columnHeader = columnMetadata.get(columnName); if (columnHeader) { filteredColumns.push({ index: index, columnName: columnName, columnHeader: columnHeader, }); } }); if (filteredColumns.length < columnMetadata.size) { var missingColumns = Array.from(columnMetadata.keys()).filter(function (columnName) { return !filteredColumns.find(function (columnHeader) { return columnHeader.columnName === columnName; }); }); throw new Error("'columnNames' is missing columns: ".concat(missingColumns)); } try { for (var rows_2 = __values(rows), rows_2_1 = rows_2.next(); !rows_2_1.done; rows_2_1 = rows_2.next()) { var row = rows_2_1.value; var dataRow = {}; try { for (var filteredColumns_1 = (e_3 = void 0, __values(filteredColumns)), filteredColumns_1_1 = filteredColumns_1.next(); !filteredColumns_1_1.done; filteredColumns_1_1 = filteredColumns_1.next()) { var _c = filteredColumns_1_1.value, index = _c.index, columnName = _c.columnName, columnHeader = _c.columnHeader; var value = row[index]; dataRow[columnName] = getValueForType(value, columnHeader.dataType); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (filteredColumns_1_1 && !filteredColumns_1_1.done && (_b = filteredColumns_1.return)) _b.call(filteredColumns_1); } finally { if (e_3) throw e_3.error; } } dataRows.push(dataRow); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (rows_2_1 && !rows_2_1.done && (_a = rows_2.return)) _a.call(rows_2); } finally { if (e_2) throw e_2.error; } } return dataRows; } exports.composeDataRowsWithType = composeDataRowsWithType; /** * Determines if an array of records is a valid array of DataRow. * We are assuming here that the rows object is non-empty. * * @param {Record<string, unknown>[]} rows - The array of records to check. * * @returns {boolean} - A boolean indicating whether the array is a valid array of data rows. */ function isValidDataRows(rows) { var e_4, _a; // Get the column names from the first row to use as a reference for subsequent rows. var columnNames = Object.keys(rows[0]); try { // Check each row and each column value to make sure they are valid DataRow values. for (var rows_3 = __values(rows), rows_3_1 = rows_3.next(); !rows_3_1.done; rows_3_1 = rows_3.next()) { var row = rows_3_1.value; for (var index = 0; index < columnNames.length; index++) { var columnName = columnNames[index]; var rowValue = row[columnName]; if (!isDataRowValue(rowValue)) { return false; } } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (rows_3_1 && !rows_3_1.done && (_a = rows_3.return)) _a.call(rows_3); } finally { if (e_4) throw e_4.error; } } // If all rows and all column values pass the validity check, return true. return true; } exports.isValidDataRows = isValidDataRows; /** * Determines if a given value is a valid value for a table row column. * * @param {unknown} value - The value to check. * * @returns {boolean} - A boolean indicating whether the value is a valid DataRow value. */ function isDataRowValue(value) { // A valid DataRow value is either null or a non-object type. return value === null || typeof value !== 'object'; } /** * Composes an array of data rows with typed values from an array of objects. * We are assuming here that the rows object is non-empty. * * @param {UnparsedDataRow[]} rows - The array of objects to use as a source of values. * @param {Map<string, ColumnHeader>} columnMetadata - A map of column headers that describes the expected types for each column. * * @returns {DataRow[]} - An array of data rows with typed values. * * @throws {Error} - If any columns are missing from the input array of objects. */ function composeDataRowsWithTypeFromObjectArray(rows, columnMetadata) { var e_5, _a, e_6, _b; // Initialize an empty array to store the composed data rows. var dataRows = []; // Get the column names from the first row to use as a reference for subsequent rows. var columnNames = Object.keys(rows[0]); // Filter the column names to only include those that have metadata in the columnMetadata map. var filteredColumns = []; columnNames.forEach(function (columnName, index) { var columnHeader = columnMetadata.get(columnName); if (columnHeader) { filteredColumns.push({ index: index, columnName: columnName, columnHeader: columnHeader, }); } }); // Check if any columns are missing from the filtered column list and throw an error if so. if (filteredColumns.length < columnMetadata.size) { var missingColumns = Array.from(columnMetadata.keys()).filter(function (columnName) { return !filteredColumns.find(function (columnHeader) { return columnHeader.columnName === columnName; }); }); throw new Error("'columnNames' is missing columns: ".concat(missingColumns)); } try { // Loop through each input object and compose a data row with typed values. for (var rows_4 = __values(rows), rows_4_1 = rows_4.next(); !rows_4_1.done; rows_4_1 = rows_4.next()) { var row = rows_4_1.value; var dataRow = {}; try { for (var filteredColumns_2 = (e_6 = void 0, __values(filteredColumns)), filteredColumns_2_1 = filteredColumns_2.next(); !filteredColumns_2_1.done; filteredColumns_2_1 = filteredColumns_2.next()) { var _c = filteredColumns_2_1.value, columnName = _c.columnName, columnHeader = _c.columnHeader; var value = row[columnName]; dataRow[columnName] = getValueForType(value, columnHeader.dataType); } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (filteredColumns_2_1 && !filteredColumns_2_1.done && (_b = filteredColumns_2.return)) _b.call(filteredColumns_2); } finally { if (e_6) throw e_6.error; } } dataRows.push(dataRow); } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (rows_4_1 && !rows_4_1.done && (_a = rows_4.return)) _a.call(rows_4); } finally { if (e_5) throw e_5.error; } } return dataRows; } exports.composeDataRowsWithTypeFromObjectArray = composeDataRowsWithTypeFromObjectArray; /** * Using a read stream is likely the most performant method for very large files, * since it reads only the first chunk of data from the file and does not retrieve the file size. */ function isFileEmpty(filepath) { var _a, e_7, _b, _c; return __awaiter(this, void 0, void 0, function () { var stream, _d, stream_1, stream_1_1, chunk, e_7_1; return __generator(this, function (_e) { switch (_e.label) { case 0: stream = fs_1.default.createReadStream(filepath); _e.label = 1; case 1: _e.trys.push([1, , 14, 15]); _e.label = 2; case 2: _e.trys.push([2, 7, 8, 13]); _d = true, stream_1 = __asyncValues(stream); _e.label = 3; case 3: return [4 /*yield*/, stream_1.next()]; case 4: if (!(stream_1_1 = _e.sent(), _a = stream_1_1.done, !_a)) return [3 /*break*/, 6]; _c = stream_1_1.value; _d = false; try { chunk = _c; if (chunk.length > 0) { return [2 /*return*/, false]; } } finally { _d = true; } _e.label = 5; case 5: return [3 /*break*/, 3]; case 6: return [3 /*break*/, 13]; case 7: e_7_1 = _e.sent(); e_7 = { error: e_7_1 }; return [3 /*break*/, 13]; case 8: _e.trys.push([8, , 11, 12]); if (!(!_d && !_a && (_b = stream_1.return))) return [3 /*break*/, 10]; return [4 /*yield*/, _b.call(stream_1)]; case 9: _e.sent(); _e.label = 10; case 10: return [3 /*break*/, 12]; case 11: if (e_7) throw e_7.error; return [7 /*endfinally*/]; case 12: return [7 /*endfinally*/]; case 13: return [2 /*return*/, true]; case 14: stream.close(); return [7 /*endfinally*/]; case 15: return [2 /*return*/]; } }); }); } exports.isFileEmpty = isFileEmpty; function getValueForType(value, type) { switch (type) { case column_header_property_1.DataType.Date: case column_header_property_1.DataType.Datetime: { if (!value) { return null; } return value; } case column_header_property_1.DataType.Int: case column_header_property_1.DataType.Float: { if (value === '' || value === undefined || value === null) { return null; } return Number(value); } case column_header_property_1.DataType.Bool: { if (value === '' || value === undefined || value === null) { return null; } return value.toLowerCase() === 'true'; } case column_header_property_1.DataType.Geometry: { if (!value) { return null; } return JSON.parse(value); } default: { if (value === undefined) { return null; } return value; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyc2UtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZXBzL3V0aWxzL3BhcnNlLXV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDBDQUFtQjtBQUVuQixvRkFBb0U7QUFNcEU7Ozs7R0FJRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxJQUFnQixFQUFFLFdBQXFCOztJQUNyRSxJQUFNLFFBQVEsR0FBYyxFQUFFLENBQUE7O1FBQzlCLEtBQWtCLElBQUEsU0FBQSxTQUFBLElBQUksQ0FBQSwwQkFBQSw0Q0FBRTtZQUFuQixJQUFNLEdBQUcsaUJBQUE7WUFDWixJQUFNLE9BQU8sR0FBWSxFQUFFLENBQUE7WUFDM0IsS0FBSyxJQUFJLEtBQUssR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLFdBQVcsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUU7Z0JBQ3ZELElBQU0sVUFBVSxHQUFHLFdBQVcsQ0FBQyxLQUFLLENBQUMsQ0FBQTtnQkFDckMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQTthQUNqQztZQUNELFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUE7U0FDdkI7Ozs7Ozs7OztJQUNELE9BQU8sUUFBUSxDQUFBO0FBQ2pCLENBQUM7QUFYRCwwQ0FXQztBQUVEOzs7Ozs7Ozs7R0FTRztBQUNILFNBQWdCLHVCQUF1QixDQUNyQyxJQUFnQixFQUNoQixXQUFxQixFQUNyQixjQUF5Qzs7SUFFekMsSUFBTSxRQUFRLEdBQWMsRUFBRSxDQUFBO0lBRTlCLElBQU0sZUFBZSxHQUF3RSxFQUFFLENBQUE7SUFDL0YsV0FBVyxDQUFDLE9BQU8sQ0FBQyxVQUFDLFVBQVUsRUFBRSxLQUFLO1FBQ3BDLElBQU0sWUFBWSxHQUFHLGNBQWMsQ0FBQyxH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