UNPKG

@supabase/realtime-js

Version:
242 lines 9.03 kB
"use strict"; /** * Helpers to convert the change Payload into native JS types. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.httpEndpointURL = exports.toTimestampString = exports.toArray = exports.toJson = exports.toNumber = exports.toBoolean = exports.convertCell = exports.convertColumn = exports.convertChangeData = exports.PostgresTypes = void 0; // Adapted from epgsql (src/epgsql_binary.erl), this module licensed under // 3-clause BSD found here: https://raw.githubusercontent.com/epgsql/epgsql/devel/LICENSE var PostgresTypes; (function (PostgresTypes) { PostgresTypes["abstime"] = "abstime"; PostgresTypes["bool"] = "bool"; PostgresTypes["date"] = "date"; PostgresTypes["daterange"] = "daterange"; PostgresTypes["float4"] = "float4"; PostgresTypes["float8"] = "float8"; PostgresTypes["int2"] = "int2"; PostgresTypes["int4"] = "int4"; PostgresTypes["int4range"] = "int4range"; PostgresTypes["int8"] = "int8"; PostgresTypes["int8range"] = "int8range"; PostgresTypes["json"] = "json"; PostgresTypes["jsonb"] = "jsonb"; PostgresTypes["money"] = "money"; PostgresTypes["numeric"] = "numeric"; PostgresTypes["oid"] = "oid"; PostgresTypes["reltime"] = "reltime"; PostgresTypes["text"] = "text"; PostgresTypes["time"] = "time"; PostgresTypes["timestamp"] = "timestamp"; PostgresTypes["timestamptz"] = "timestamptz"; PostgresTypes["timetz"] = "timetz"; PostgresTypes["tsrange"] = "tsrange"; PostgresTypes["tstzrange"] = "tstzrange"; })(PostgresTypes || (exports.PostgresTypes = PostgresTypes = {})); /** * Takes an array of columns and an object of string values then converts each string value * to its mapped type. * * @param {{name: String, type: String}[]} columns * @param {Object} record * @param {Object} options The map of various options that can be applied to the mapper * @param {Array} options.skipTypes The array of types that should not be converted * * @example convertChangeData([{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age:'33'}, {}) * //=>{ first_name: 'Paul', age: 33 } */ const convertChangeData = (columns, record, options = {}) => { var _a; const skipTypes = (_a = options.skipTypes) !== null && _a !== void 0 ? _a : []; if (!record) { return {}; } return Object.keys(record).reduce((acc, rec_key) => { acc[rec_key] = (0, exports.convertColumn)(rec_key, columns, record, skipTypes); return acc; }, {}); }; exports.convertChangeData = convertChangeData; /** * Converts the value of an individual column. * * @param {String} columnName The column that you want to convert * @param {{name: String, type: String}[]} columns All of the columns * @param {Object} record The map of string values * @param {Array} skipTypes An array of types that should not be converted * @return {object} Useless information * * @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, []) * //=> 33 * @example convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], {first_name: 'Paul', age: '33'}, ['int4']) * //=> "33" */ const convertColumn = (columnName, columns, record, skipTypes) => { const column = columns.find((x) => x.name === columnName); const colType = column === null || column === void 0 ? void 0 : column.type; const value = record[columnName]; if (colType && !skipTypes.includes(colType)) { return (0, exports.convertCell)(colType, value); } return noop(value); }; exports.convertColumn = convertColumn; /** * If the value of the cell is `null`, returns null. * Otherwise converts the string value to the correct type. * @param {String} type A postgres column type * @param {String} value The cell value * * @example convertCell('bool', 't') * //=> true * @example convertCell('int8', '10') * //=> 10 * @example convertCell('_int4', '{1,2,3,4}') * //=> [1,2,3,4] */ const convertCell = (type, value) => { // if data type is an array if (type.charAt(0) === '_') { const dataType = type.slice(1, type.length); return (0, exports.toArray)(value, dataType); } // If not null, convert to correct type. switch (type) { case PostgresTypes.bool: return (0, exports.toBoolean)(value); case PostgresTypes.float4: case PostgresTypes.float8: case PostgresTypes.int2: case PostgresTypes.int4: case PostgresTypes.int8: case PostgresTypes.numeric: case PostgresTypes.oid: return (0, exports.toNumber)(value); case PostgresTypes.json: case PostgresTypes.jsonb: return (0, exports.toJson)(value); case PostgresTypes.timestamp: return (0, exports.toTimestampString)(value); // Format to be consistent with PostgREST case PostgresTypes.abstime: // To allow users to cast it based on Timezone case PostgresTypes.date: // To allow users to cast it based on Timezone case PostgresTypes.daterange: case PostgresTypes.int4range: case PostgresTypes.int8range: case PostgresTypes.money: case PostgresTypes.reltime: // To allow users to cast it based on Timezone case PostgresTypes.text: case PostgresTypes.time: // To allow users to cast it based on Timezone case PostgresTypes.timestamptz: // To allow users to cast it based on Timezone case PostgresTypes.timetz: // To allow users to cast it based on Timezone case PostgresTypes.tsrange: case PostgresTypes.tstzrange: return noop(value); default: // Return the value for remaining types return noop(value); } }; exports.convertCell = convertCell; const noop = (value) => { return value; }; const toBoolean = (value) => { switch (value) { case 't': return true; case 'f': return false; default: return value; } }; exports.toBoolean = toBoolean; const toNumber = (value) => { if (typeof value === 'string') { const parsedValue = parseFloat(value); if (!Number.isNaN(parsedValue)) { return parsedValue; } } return value; }; exports.toNumber = toNumber; const toJson = (value) => { if (typeof value === 'string') { try { return JSON.parse(value); } catch (error) { console.log(`JSON parse error: ${error}`); return value; } } return value; }; exports.toJson = toJson; /** * Converts a Postgres Array into a native JS array * * @example toArray('{}', 'int4') * //=> [] * @example toArray('{"[2021-01-01,2021-12-31)","(2021-01-01,2021-12-32]"}', 'daterange') * //=> ['[2021-01-01,2021-12-31)', '(2021-01-01,2021-12-32]'] * @example toArray([1,2,3,4], 'int4') * //=> [1,2,3,4] */ const toArray = (value, type) => { if (typeof value !== 'string') { return value; } const lastIdx = value.length - 1; const closeBrace = value[lastIdx]; const openBrace = value[0]; // Confirm value is a Postgres array by checking curly brackets if (openBrace === '{' && closeBrace === '}') { let arr; const valTrim = value.slice(1, lastIdx); // TODO: find a better solution to separate Postgres array data try { arr = JSON.parse('[' + valTrim + ']'); } catch (_) { // WARNING: splitting on comma does not cover all edge cases arr = valTrim ? valTrim.split(',') : []; } return arr.map((val) => (0, exports.convertCell)(type, val)); } return value; }; exports.toArray = toArray; /** * Fixes timestamp to be ISO-8601. Swaps the space between the date and time for a 'T' * See https://github.com/supabase/supabase/issues/18 * * @example toTimestampString('2019-09-10 00:00:00') * //=> '2019-09-10T00:00:00' */ const toTimestampString = (value) => { if (typeof value === 'string') { return value.replace(' ', 'T'); } return value; }; exports.toTimestampString = toTimestampString; const httpEndpointURL = (socketUrl) => { const wsUrl = new URL(socketUrl); wsUrl.protocol = wsUrl.protocol.replace(/^ws/i, 'http'); wsUrl.pathname = wsUrl.pathname .replace(/\/+$/, '') // remove all trailing slashes .replace(/\/socket\/websocket$/i, '') // remove the socket/websocket path .replace(/\/socket$/i, '') // remove the socket path .replace(/\/websocket$/i, ''); // remove the websocket path if (wsUrl.pathname === '' || wsUrl.pathname === '/') { wsUrl.pathname = '/api/broadcast'; } else { wsUrl.pathname = wsUrl.pathname + '/api/broadcast'; } return wsUrl.href; }; exports.httpEndpointURL = httpEndpointURL; //# sourceMappingURL=transformers.js.map