@flightstream/utils-arrow
Version:
Advanced utilities for working with Arrow data and Flight protocol in FlightStream for Node.js
279 lines (261 loc) • 8.47 kB
JavaScript
/**
* TypeTransformer - Handles all data transformation/parsing logic
*
* This class provides methods to safely convert raw values to Arrow-compatible
* values. It handles null values, type conversion, and error recovery.
*/
export class TypeTransformer {
constructor() {
// No configuration needed for basic transformers
}
/**
* Safe integer parsing with null handling
* @param {*} value - Value to parse
* @returns {number|null} Parsed integer or null
*/
safeParseInt(value) {
if (value === null || value === undefined) return null;
const parsed = parseInt(value, 10);
return isNaN(parsed) ? null : parsed;
}
/**
* Safe float parsing with null handling
* @param {*} value - Value to parse
* @returns {number|null} Parsed float or null
*/
safeParseFloat(value) {
if (value === null || value === undefined) return null;
const parsed = parseFloat(value);
return isNaN(parsed) ? null : parsed;
}
/**
* Safe date parsing to milliseconds with null handling
* @param {*} value - Value to parse as date
* @returns {number|null} Date in milliseconds or null
*/
safeParseDateMillis(value) {
if (value === null || value === undefined) return null;
try {
const date = value instanceof Date ? value : new Date(value);
return isNaN(date.getTime()) ? null : date.getTime();
} catch (error) {
return null;
}
}
/**
* Safe date parsing to days with null handling
* @param {*} value - Value to parse as date
* @returns {number|null} Date in days or null
*/
safeParseDateDays(value) {
if (value === null || value === undefined) return null;
try {
const date = value instanceof Date ? value : new Date(value);
const timeMs = date.getTime();
return isNaN(timeMs) ? null : Math.floor(timeMs / (1000 * 60 * 60 * 24));
} catch (error) {
return null;
}
}
/**
* Safe timestamp parsing with unit conversion
* @param {*} value - Value to parse as timestamp
* @param {number} unitMultiplier - Multiplier for unit conversion
* @returns {number|null} Timestamp in specified units or null
*/
safeParseTimestamp(value, unitMultiplier) {
if (value === null || value === undefined) return null;
try {
const date = value instanceof Date ? value : new Date(value);
const timeMs = date.getTime();
return isNaN(timeMs) ? null : Math.floor(timeMs * unitMultiplier);
} catch (error) {
return null;
}
}
/**
* Safe time parsing with unit conversion
* @param {*} value - Value to parse as time
* @param {number} unitMultiplier - Multiplier for unit conversion
* @returns {number|null} Time in specified units or null
*/
safeParseTime(value, unitMultiplier) {
if (value === null || value === undefined) return null;
try {
// Handle various time formats
if (typeof value === 'string') {
// Parse time strings like "12:30:45"
const parts = value.split(':').map(Number);
if (parts.length >= 3) {
const seconds = parts[0] * 3600 + parts[1] * 60 + parts[2];
return Math.floor(seconds * unitMultiplier);
}
}
// Fallback to date parsing
const date = value instanceof Date ? value : new Date(value);
const timeMs = date.getTime();
return isNaN(timeMs) ? null : Math.floor(timeMs * unitMultiplier);
} catch (error) {
return null;
}
}
/**
* Safe binary parsing
* @param {*} value - Value to parse as binary
* @returns {Uint8Array|null} Binary data or null
*/
safeParseBinary(value) {
if (value === null || value === undefined) return null;
try {
if (value instanceof Uint8Array) return value;
if (value instanceof Buffer) return new Uint8Array(value);
if (typeof value === 'string') {
// Try to parse as base64
return new Uint8Array(Buffer.from(value, 'base64'));
}
if (Array.isArray(value)) return new Uint8Array(value);
return null;
} catch (error) {
return null;
}
}
/**
* Safe decimal parsing
* @param {*} value - Value to parse as decimal
* @param {arrow.DataType} arrowType - Arrow decimal type
* @returns {*} Decimal value or null
*/
safeParseDecimal(value, _arrowType) {
if (value === null || value === undefined) return null;
try {
// For now, return the value as-is and let Arrow handle the conversion
// This is a simplified implementation - in practice, you might want
// more sophisticated decimal handling based on precision/scale
return value;
} catch (error) {
return null;
}
}
/**
* Safe list parsing
* @param {*} value - Value to parse as list
* @returns {Array|null} List value or null
*/
safeParseList(value) {
if (value === null || value === undefined) return null;
try {
if (Array.isArray(value)) return value;
if (typeof value === 'string') {
// Try to parse JSON string
return JSON.parse(value);
}
return [value]; // Wrap single value in array
} catch (error) {
return null;
}
}
/**
* Safe struct parsing
* @param {*} value - Value to parse as struct
* @returns {Object|null} Struct value or null
*/
safeParseStruct(value) {
if (value === null || value === undefined) return null;
try {
if (typeof value === 'object' && !Array.isArray(value)) return value;
if (typeof value === 'string') {
// Try to parse JSON string
return JSON.parse(value);
}
return { value }; // Wrap single value in object
} catch (error) {
return null;
}
}
/**
* Safe map parsing
* @param {*} value - Value to parse as map
* @returns {Array|null} Map entries or null
*/
safeParseMap(value) {
if (value === null || value === undefined) return null;
try {
if (Array.isArray(value)) return value;
if (typeof value === 'object' && !Array.isArray(value)) {
// Convert object to key-value pairs
return Object.entries(value);
}
if (typeof value === 'string') {
// Try to parse JSON string
const parsed = JSON.parse(value);
if (typeof parsed === 'object' && !Array.isArray(parsed)) {
return Object.entries(parsed);
}
return parsed;
}
return null;
} catch (error) {
return null;
}
}
/**
* Safe interval parsing
* @param {*} value - Value to parse as interval
* @returns {*} Interval value or null
*/
safeParseInterval(value) {
if (value === null || value === undefined) return null;
try {
// For now, return the value as-is and let Arrow handle the conversion
// This is a simplified implementation
return value;
} catch (error) {
return null;
}
}
/**
* Safe duration parsing with unit conversion
* @param {*} value - Value to parse as duration
* @param {number} unitMultiplier - Multiplier for unit conversion
* @returns {number|null} Duration in specified units or null
*/
safeParseDuration(value, unitMultiplier) {
if (value === null || value === undefined) return null;
try {
if (typeof value === 'number') return Math.floor(value * unitMultiplier);
if (typeof value === 'string') {
// Try to parse duration strings like "1h30m" or "90s"
const duration = this.parseDurationString(value);
return duration ? Math.floor(duration * unitMultiplier) : null;
}
return null;
} catch (error) {
return null;
}
}
/**
* Parse duration string to milliseconds
* @param {string} durationStr - Duration string like "1h30m" or "90s"
* @returns {number|null} Duration in milliseconds or null
*/
parseDurationString(durationStr) {
try {
const regex = /(\d+)([dhms])/g;
let totalMs = 0;
let match;
while ((match = regex.exec(durationStr)) !== null) {
const value = parseInt(match[1], 10);
const unit = match[2];
switch (unit) {
case 'd': totalMs += value * 24 * 60 * 60 * 1000; break;
case 'h': totalMs += value * 60 * 60 * 1000; break;
case 'm': totalMs += value * 60 * 1000; break;
case 's': totalMs += value * 1000; break;
}
}
return totalMs > 0 ? totalMs : null;
} catch (error) {
return null;
}
}
}