mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
177 lines
5.6 KiB
JavaScript
177 lines
5.6 KiB
JavaScript
// # Lifted from epgsql (src/epgsql_binary.erl), this module licensed under
|
|
// # 3-clause BSD found here: https://raw.githubusercontent.com/epgsql/epgsql/devel/LICENSE
|
|
|
|
/**
|
|
* 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} records
|
|
* @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 }
|
|
*/
|
|
export const convertChangeData = (columns, records, options = {}) => {
|
|
let result = {}
|
|
let skipTypes = typeof options.skipTypes !== 'undefined' ? options.skipTypes : []
|
|
Object.entries(records).map(([key, value]) => {
|
|
result[key] = convertColumn(key, columns, records, skipTypes)
|
|
})
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* 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} records 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'}], ['Paul', '33'], [])
|
|
* //=>
|
|
* 33
|
|
*
|
|
* @example
|
|
* convertColumn('age', [{name: 'first_name', type: 'text'}, {name: 'age', type: 'int4'}], ['Paul', '33'], ['int4'])
|
|
* //=>
|
|
* "33"
|
|
*/
|
|
export const convertColumn = (columnName, columns, records, skipTypes) => {
|
|
let column = columns.find(x => x.name == columnName)
|
|
if(skipTypes.includes(column.type)) return noop(records[columnName])
|
|
else return convertCell(column.type, records[columnName])
|
|
}
|
|
|
|
/**
|
|
* 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} stringValue The cell value
|
|
*
|
|
* @example
|
|
* convertCell('bool', 'true')
|
|
* //=>
|
|
* true
|
|
*
|
|
* @example
|
|
* convertCell('int8', '10')
|
|
* //=>
|
|
* 10
|
|
*/
|
|
export const convertCell = (type, stringValue) => {
|
|
try {
|
|
if (stringValue === null) return null
|
|
|
|
// If not null, convert to correct type.
|
|
switch (type) {
|
|
case 'abstime':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'bool':
|
|
return toBoolean(stringValue)
|
|
case 'date':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'daterange':
|
|
return toDateRange(stringValue)
|
|
case 'float4':
|
|
return toFloat(stringValue)
|
|
case 'float8':
|
|
return toFloat(stringValue)
|
|
case 'int2':
|
|
return toInt(stringValue)
|
|
case 'int4':
|
|
return toInt(stringValue)
|
|
case 'int4range':
|
|
return toIntRange(stringValue)
|
|
case 'int8':
|
|
return toInt(stringValue)
|
|
case 'int8range':
|
|
return toIntRange(stringValue)
|
|
case 'json':
|
|
return toJson(stringValue)
|
|
case 'jsonb':
|
|
return toJson(stringValue)
|
|
case 'money':
|
|
return toFloat(stringValue)
|
|
case 'numeric':
|
|
return toFloat(stringValue)
|
|
case 'oid':
|
|
return toInt(stringValue)
|
|
case 'reltime':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'time':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'timestamp':
|
|
return toTimestampString(stringValue) // Format to be consistent with PostgREST
|
|
case 'timestamptz':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'timetz':
|
|
return noop(stringValue) // To allow users to cast it based on Timezone
|
|
case 'tsrange':
|
|
return toDateRange(stringValue)
|
|
case 'tstzrange':
|
|
return toDateRange(stringValue)
|
|
default:
|
|
// All the rest will be returned as strings
|
|
return noop(stringValue)
|
|
}
|
|
} catch (error) {
|
|
console.log(`Could not convert cell of type ${type} and value ${stringValue}`)
|
|
return stringValue
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Passes back the raw string value
|
|
*/
|
|
const noop = stringValue => {
|
|
return stringValue
|
|
}
|
|
const toBoolean = stringValue => {
|
|
switch (stringValue) {
|
|
case 't':
|
|
return true
|
|
case 'f':
|
|
return false
|
|
default:
|
|
return null
|
|
}
|
|
}
|
|
const toDate = stringValue => {
|
|
return new Date(stringValue)
|
|
}
|
|
const toDateRange = stringValue => {
|
|
let arr = JSON.parse(stringValue)
|
|
return [new Date(arr[0]), new Date(arr[1])]
|
|
}
|
|
const toFloat = stringValue => {
|
|
return parseFloat(stringValue)
|
|
}
|
|
const toInt = stringValue => {
|
|
return parseInt(stringValue)
|
|
}
|
|
const toIntRange = stringValue => {
|
|
let arr = JSON.parse(stringValue)
|
|
return [parseInt(arr[0]), parseInt(arr[1])]
|
|
}
|
|
const toJson = stringValue => {
|
|
return JSON.parse(stringValue)
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @returns {string}
|
|
*
|
|
* @example
|
|
* toTimestampString('2019-09-10 00:00:00')
|
|
* //=>
|
|
* '2019-09-10T00:00:00'
|
|
*/
|
|
const toTimestampString = stringValue => {
|
|
return stringValue.replace(' ', 'T')
|
|
} |